https://codeforces.com/contest/487/problem/E
显然割点走过去就走不回来了...可以看出题目跟点双有关
有一个结论:如果在点双中有不同的点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 }
原文地址:https://www.cnblogs.com/hehe54321/p/9803900.html