BZOJ 2959 长跑 LCT+动态边双
题意:
支持加入边,修改点权,询问两点间走一条路径的最大点权和。不一定是树。
分析:
这个题我们需要知道,假如两点间有环,那么无论如何,这个环上所有的价值都可以被我们获得。
有环,还有这个性质,我们可以自然而然的想到边双联通分量缩点,但是我们不能对于每次加边就重构一下图,更不能每次询问都求一遍最大路,所以我们就需要一个灵活的LCT来维护我们的操作。
我们用并查集辅助,用一个并查集维护连通性,再用一个并查集维护每个原始点属于哪个新的边双联通分量。
当我们连接一条边时,如果两个点不连通,那么我们直接将其连通。
如果本身已经连通,那么我们就在LCT上把这两个点之间的链搞到一个splay上,然后dfs一遍,把链上所有的点都弄进一个双连通分量里(就是用并查集并起来),继而把这些点从splay上删掉,只留一个根节点,将整个环的价值赋给它。
修改点权的时候,我们直接把原始点的权值修改,然后算出所在连通分量的总权值应该怎样变化即可。
至此,回答询问也就是自然而然的事情了。
代码:
1 #include<bits/stdc++.h> 2 #define max(a,b,c) max(max(a,b),c) 3 #define lc(x) t[x][0] 4 #define rc(x) t[x][1] 5 using namespace std; 6 const int N=150005; 7 int t[N][2],rev[N],val[N],sm[N],fu[N]; 8 int s[N],tp,n,m,k,fa[N],Fa[N],q,v[N]; 9 //并查集----------------------------------------↓ 10 int get(int x){ 11 return x==fa[x]?x:fa[x]=get(fa[x]); 12 } int Get(int x){ 13 return x==Fa[x]?x:Fa[x]=Get(Fa[x]); 14 } 15 //并查集----------------------------------------↑ 16 //LCT-------------------------------------------↓ 17 void pushup(int x){ 18 sm[x]=sm[lc(x)]+sm[rc(x)]+val[x]; 19 } void revers(int x){ 20 rev[x]^=1;swap(lc(x),rc(x)); 21 } void pushdown(int x){ 22 if(rev[x]){ 23 if(lc(x)) revers(lc(x)); 24 if(rc(x)) revers(rc(x)); 25 } rev[x]=0;return ; 26 } bool pdrt(int x){ 27 return lc(get(fu[x]))!=x&&rc(get(fu[x]))!=x; 28 } void rotate(int x){ 29 int y=get(fu[x]);int z=get(fu[y]); 30 int dy=(rc(y)==x),dz=(rc(z)==y); 31 if(!pdrt(y)) t[z][dz]=x; 32 t[y][dy]=t[x][dy^1];fu[t[y][dy]]=y; 33 t[x][dy^1]=y;fu[y]=x;fu[x]=z;pushup(y); 34 } void splay(int x){ 35 s[++tp]=x; 36 for(int i=x;!pdrt(i);i=fu[i]) 37 s[++tp]=get(fu[i]); 38 while(tp) pushdown(s[tp--]); 39 while(!pdrt(x)){ 40 int y=get(fu[x]);int z=get(fu[y]); 41 if(!pdrt(y)) 42 if(rc(y)==x^rc(z)==y) rotate(x); 43 else rotate(y);rotate(x); 44 } pushup(x); 45 } void access(int x){ 46 for(int i=0;x;x=get(fu[x])) 47 splay(x),rc(x)=i,i=x; 48 } void mkrt(int x){ 49 access(x);splay(x);revers(x); 50 } int fdrt(int x){ 51 access(x),splay(x); 52 while(lc(x)) pushdown(x),x=lc(x); 53 return x; 54 } void split(int x,int y){ 55 mkrt(x);access(y);splay(y); 56 } void link(int x,int y){ 57 mkrt(x);if(fdrt(y)!=x) fu[x]=y; 58 } void cut(int x,int y){ 59 mkrt(x); 60 if(fdrt(y)==x&&fu[y]==x&&!rc(x)) 61 fu[x]=t[y][0]=0;pushup(y); 62 } 63 //LCT-------------------------------------------↑ 64 //DFS-------------------------------------------↓ 65 void dfs(int x,int y){ 66 fa[x]=y;pushdown(x); 67 if(lc(x)) dfs(lc(x),y); 68 if(rc(x)) dfs(rc(x),y); 69 } 70 //DFS-------------------------------------------↑ 71 int main(){ 72 scanf("%d%d",&n,&m); 73 for(int i=1;i<=n;i++) 74 scanf("%d",&v[i]),Fa[i]=i, 75 val[i]=s[i]=v[i],fa[i]=i; 76 for(int i=1,op,a,b;i<=m;i++){ 77 scanf("%d%d%d",&op,&a,&b); 78 if(op==1){ 79 a=get(a),b=get(b); 80 if(a==b) continue; 81 split(a,b); 82 if(Get(a)!=Get(b)) 83 fu[a]=b,Fa[Fa[a]]=Fa[b]; 84 else val[b]=sm[b],dfs(b,b), 85 t[b][0]=t[b][1]=0; 86 } int d;if(op==2) 87 d=a,a=get(a),splay(a), 88 val[a]+=b-v[d],v[d]=b,pushup(a); 89 if(op==3){ 90 a=get(a),b=get(b); 91 if(Get(a)!=Get(b)) puts("-1"); 92 else split(a,b),printf("%d\n",sm[b]); 93 } 94 } return 0; 95 }