Tourists Codeforces - 487E

https://codeforces.com/contest/487/problem/E

http://uoj.ac/problem/30

显然割点走过去就走不回来了...可以看出题目跟点双有关

有一个结论:如果在点双中有不同的点a,b,c,那么一定存在点不重复的路径从a到c再到b。

证明(摘自https://codeforces.com/blog/entry/14832):

显然这样的点双中,点数>=3,因此移除任意点或任意边,仍然连通

新建一张网络流图。用边(u,v,w)表示从u到v容量为w的边

对于原点双中每一条边(u,v),建新边(u,v,1),(v,u,1)

新建点S,T,建边(S,c,2),(a,T,1),(b,T,1)

用拆点的方法,给S,T,c外的每一个点1的容量(拆点过程略)

此时,显然如果S到T的最大流为2,那么存在合法方案

最大流=最小割。显然最小割<=2(割掉(a,T)与(b,T)的边)。割掉新图中任意一条权值为1的边(除(a,T),(b,T)),对应删除原点双的一条边或一个点,显然删除之后原图仍然连通,则新图也连通。因此最小割>1。所以最小割=2

就是说,如果走的时候要穿过一个点双(任意点开始,任意点结束),那么一定可以找到一条合法路径经过点双内权值最小的点

有一个想法:

可以点双缩点成树(圆方树)(每个点双新建一个点,向点双中所有点连边,删除原图中所有边)

(树中代表一个点双的点的权值是点双中点权的最小值)

然后查询就是树上两点路径上最小值,修改就是单点修改(每个点双用一个multiset维护点双中所有点的权值。修改非割点就直接在它属于的点双的multiset中改,如果multiset中最小值变了就对应修改维护最小值的数据结构;修改割点方法在后面),用树剖维护即可

好像还不怎么对。。割点也是属于点双的,但是修改割点权值显然不能暴力修改其属于的所有点双

看了题解,方法是:每个割点就当做属于它在缩点树中的父亲(这个父亲一定代表一个点双;如果不存在父亲就不用维护),每次修改就在这个父亲的multiset那里改;同时每次查询的时候,如果两点的lca代表一个点双,那么除两点路径上最小值外还要考虑lca的父亲(一定是个割点;如果不存在父亲就不用额外查)

然而真的码不动。。5K代码,续了一下午A掉

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<vector>
  5 #include<set>
  6 using namespace std;
  7 #define fi first
  8 #define se second
  9 #define mp make_pair
 10 #define pb push_back
 11 typedef long long ll;
 12 typedef unsigned long long ull;
 13 typedef pair<int,int> pii;
 14 struct E
 15 {
 16     int to,nxt;
 17 };
 18 int a[200010];
 19 int n,m,qq;
 20 namespace S
 21 {
 22 #define lc (num<<1)
 23 #define rc (num<<1|1)
 24 int d[800100];
 25 void setx(int L,int x,int l,int r,int num)
 26 {
 27     if(l==r)    {d[num]=x;return;}
 28     int mid=l+((r-l)>>1);
 29     if(L<=mid)    setx(L,x,l,mid,lc);
 30     else    setx(L,x,mid+1,r,rc);
 31     d[num]=min(d[lc],d[rc]);
 32 }
 33 int gmin(int L,int R,int l,int r,int num)
 34 {
 35     if(L<=l&&r<=R)    return d[num];
 36     int mid=l+((r-l)>>1);int ans=0x3f3f3f3f;
 37     if(L<=mid)    ans=min(ans,gmin(L,R,l,mid,lc));
 38     if(mid<R)    ans=min(ans,gmin(L,R,mid+1,r,rc));
 39     return ans;
 40 }
 41 int getmin(int L,int R,int l,int r,int num)
 42 {
 43     if(L>R)    swap(L,R);
 44     //printf("19t%d %d %d\n",L,R,gmin(L,R,l,r,num));
 45     return gmin(L,R,l,r,num);
 46 }
 47 }
 48 int cnt;
 49 int bno[100010];
 50 bool iscut[100010];
 51 namespace T
 52 {
 53 E e[400100];
 54 int f1[200100],ne;
 55 void me(int x,int y)
 56 {
 57     e[++ne].to=y;e[ne].nxt=f1[x];f1[x]=ne;
 58     e[++ne].to=x;e[ne].nxt=f1[y];f1[y]=ne;
 59 }
 60 bool vis[200100];
 61 int sz[200100],hson[200100],tp[200100],dep[200100];
 62 void dfs1(int u,int fa)
 63 {
 64     sz[u]=1;
 65     vis[u]=1;
 66     for(int k=f1[u];k;k=e[k].nxt)
 67         if(e[k].to!=fa)
 68         {
 69             dep[e[k].to]=dep[u]+1;
 70             dfs1(e[k].to,u);
 71             sz[u]+=sz[e[k].to];
 72             if(sz[e[k].to]>sz[hson[u]])
 73                 hson[u]=e[k].to;
 74         }
 75 }
 76 int ar[200100],lp[200100],f[200100];
 77 void dfs2(int u,int fa)
 78 {
 79     ar[++ar[0]]=u;lp[u]=ar[0];
 80     f[u]=fa;
 81     if(u==hson[fa])    tp[u]=tp[fa];
 82     else    tp[u]=u;
 83     if(hson[u])    dfs2(hson[u],u);
 84     for(int k=f1[u];k;k=e[k].nxt)
 85         if(e[k].to!=fa&&e[k].to!=hson[u])
 86             dfs2(e[k].to,u);
 87 }
 88 multiset<int> s[100100];//s[i]维护i号点双里面所有非割点的权值
 89 void update2(int x)
 90 {
 91     a[x+n]=*s[x].begin();
 92     //printf("9t%d %d\n",x,a[x+n]);
 93     S::setx(lp[x+n],a[x+n],1,n+cnt,1);
 94 }
 95 void change(int x,int y)
 96 {
 97     if(!iscut[x])
 98     {
 99         s[bno[x]].erase(s[bno[x]].find(a[x]));
100         s[bno[x]].insert(a[x]=y);
101         update2(bno[x]);
102     }
103     else
104     {
105         if(f[x])
106         {
107             s[f[x]-n].erase(s[f[x]-n].find(a[x]));
108             s[f[x]-n].insert(y);
109             update2(f[x]-n);
110         }
111         a[x]=y;
112         S::setx(lp[x],y,1,n+cnt,1);
113     }
114 }
115 int query(int x,int y)
116 {
117     if(x==y)    return a[x];
118     //printf("99t%d %d\n",x,y);
119     //if(!iscut[x])    x=n+bno[x];
120     //if(!iscut[y])    y=n+bno[y];
121     int ans=0x3f3f3f3f;
122     while(tp[x]!=tp[y])
123     {
124         if(dep[tp[x]]<dep[tp[y]])    swap(x,y);
125         //printf("7t%d %d\n",x,y);
126         ans=min(ans,S::getmin(lp[x],lp[tp[x]],1,n+cnt,1));
127         x=f[tp[x]];
128     }
129     ans=min(ans,S::getmin(lp[x],lp[y],1,n+cnt,1));
130     if(dep[x]>dep[y])    swap(x,y);
131     if(x>n&&f[x])    ans=min(ans,a[f[x]]);
132     return ans;
133 }
134 void work()
135 {
136     int i;
137     /*
138     for(i=1;i<=n+cnt;i++)
139         for(int k=f1[i];k;k=e[k].nxt)
140             printf("1t%d %d\n",i,e[k].to);
141     for(i=1;i<=n;i++)
142         printf("%d ",bno[i]);
143     puts("t2");
144     for(i=1;i<=n;i++)
145         printf("%d ",int(iscut[i]));
146     puts("t3");
147     */
148     for(i=1;i<=n+cnt;i++)
149         if(!vis[i])
150         {
151             dfs1(i,0);
152             dfs2(i,0);
153         }
154     /*
155     for(i=1;i<=ar[0];i++)
156         printf("%d ",ar[i]);
157     puts("t4");
158     for(i=1;i<=n+cnt;i++)
159         printf("%d ",lp[i]);
160     puts("t5");
161     for(i=1;i<=n+cnt;i++)
162         printf("6t%d %d\n",f[i],tp[i]);
163     */
164     for(i=1;i<=n;i++)
165         if(!iscut[i])
166         {
167             s[bno[i]].insert(a[i]);
168             S::setx(lp[i],0x3f3f3f3f,1,n+cnt,1);
169         }
170         else
171         {
172             if(f[i])
173             {
174                 s[f[i]-n].insert(a[i]);
175             }
176             S::setx(lp[i],a[i],1,n+cnt,1);
177         }
178     for(i=1;i<=cnt;i++)
179         update2(i);
180     //for(i=1;i<=ar[0];i++)
181     //    printf("16t%d\n",S::getmin(i,i,1,n+cnt,1));
182 }
183 
184 }
185 namespace G
186 {
187 E e[200100];
188 int f1[100010],ne=1;
189 void me(int x,int y)
190 {
191     e[++ne].to=y;e[ne].nxt=f1[x];f1[x]=ne;
192     e[++ne].to=x;e[ne].nxt=f1[y];f1[y]=ne;
193 }
194 int dfc,dfn[100010];
195 pii st[100010];int tp;
196 int dfs(int u,int last)
197 {
198     //printf("3t%d %d\n",u,last);
199     int k,v,lowu=dfn[u]=++dfc,chi=0,lowv;pii x;
200     for(k=f1[u];k;k=e[k].nxt)
201     {
202         v=e[k].to;
203         if(!dfn[v])
204         {
205             st[++tp]=mp(u,v);++chi;
206             lowv=dfs(v,k);lowu=min(lowu,lowv);
207             if(lowv>=dfn[u])
208             {
209                 //printf("4t%d %d\n",u,v);
210                 iscut[u]=1;
211                 ++cnt;
212                 for(;;)
213                 {
214                     x=st[tp--];
215                     if(bno[x.fi]!=cnt)
216                     {
217                         bno[x.fi]=cnt;
218                         T::me(n+cnt,x.fi);
219                     }
220                     if(bno[x.se]!=cnt)
221                     {
222                         bno[x.se]=cnt;
223                         T::me(n+cnt,x.se);
224                     }
225                     if(x.fi==u&&x.se==v)    break;
226                 }
227             }
228         }
229         else if(dfn[v]<dfn[u]&&k!=(last^1))
230         {
231             st[++tp]=mp(u,v);
232             lowu=min(lowu,dfn[v]);
233         }
234     }
235     if(!last&&chi==1)    iscut[u]=0;
236     //printf("5t%d %d %d\n",u,lowu,dfn[u]);
237     return lowu;
238 }
239 }
240 
241 
242 int main()
243 {
244     char tmp[233];
245     int i,x,y;
246     scanf("%d%d%d",&n,&m,&qq);
247     for(i=1;i<=n;i++)    scanf("%d",&a[i]);
248     for(i=1;i<=m;i++)
249     {
250         scanf("%d%d",&x,&y);
251         G::me(x,y);
252     }
253     for(i=1;i<=n;i++)
254         if(!G::dfn[i])
255             G::dfs(i,0);
256     T::work();
257     while(qq--)
258     {
259         scanf("%s%d%d",tmp,&x,&y);
260         if(tmp[0]=='C')
261         {
262             T::change(x,y);
263         }
264         else
265         {
266             printf("%d\n",T::query(x,y));
267         }
268     }
269     return 0;
270 }
View Code

 

posted @ 2018-10-17 22:27  hehe_54321  阅读(196)  评论(0编辑  收藏  举报
AmazingCounters.com