[BZOJ2959]长跑(LCT+并查集)
用LCT支持:在线加边,单点修改,求一个两个点路径上的所有边BCC的点权和。
用LCT维护边BCC的形态(即缩边双之后的树),2,3操作都是LCT基本操作,重点考虑加边操作。
当这条边的两个端点属于同一BCC时显然没有任何影响。当两个端点不在同一个连通块里时直接在LCT上做link(bel[x],bel[y])即可。
当两个端点在同一个连通块里但不在同一个BCC中时,相当于将(缩点后的)树上两个点之间的路径全部缩成一个点。
由于过程中有频繁的点合并操作,所以再拿一个并查集记录每个BCC目前真正属于哪个BCC(即它被合并到哪个点去了),链合并的时候,先split(x,y)分离出这条链,再将链上所有点的fa[](并查集上的父亲)全部设为y,再将y左子树整个删去。在LCT操作中,我们所有的f[x](LCT上的父亲)全部变为find(f[x]),这样那些链上连出去的虚子树就能找到自己的新父亲(y)了。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 using namespace std; 5 6 const int N=150010; 7 int n,m,op,x,y,v[N],f[N],fa1[N],fa2[N],c[N][2],w[N],sm[N],rev[N]; 8 9 int get1(int x){ return x==fa1[x] ? x : fa1[x]=get1(fa1[x]); } 10 int get2(int x){ return x==fa2[x] ? x : fa2[x]=get2(fa2[x]); } 11 void upd(int x){ sm[x]=sm[c[x][0]]+sm[c[x][1]]+w[x]; } 12 void push(int x){ if (rev[x]) swap(c[x][0],c[x][1]),rev[c[x][0]]^=1,rev[c[x][1]]^=1,rev[x]=0; } 13 bool isrt(int x){ return c[get1(f[x])][1]!=x && c[get1(f[x])][0]!=x; } 14 void pd(int x){ if (!isrt(x)) pd(get1(f[x])); push(x); } 15 16 void rot(int x){ 17 int y=get1(f[x]),z=get1(f[y]),w=(c[y][1]==x); 18 if (!isrt(y)) c[z][c[z][1]==y]=x; 19 f[x]=z; f[y]=x; f[c[x][w^1]]=y; 20 c[y][w]=c[x][w^1]; c[x][w^1]=y; upd(y); 21 } 22 23 void splay(int x){ 24 for (pd(x); !isrt(x); rot(x)){ 25 int y=get1(f[x]),z=get1(f[y]); 26 if (!isrt(y)) rot((c[y][0]==x)^(c[z][0]==y)?x:y); 27 } 28 upd(x); 29 } 30 31 void access(int x){ for (int y=0; x; y=x,x=get1(f[x])) splay(x),c[x][1]=y,upd(x); } 32 void mkrt(int x){ access(x); splay(x); rev[x]^=1; } 33 void link(int x,int y){ mkrt(x); f[x]=y; } 34 void split(int x,int y){ mkrt(x); access(y); splay(y); } 35 void cut(int x,int y){ split(x,y); c[y][0]=f[x]=0; upd(y); } 36 37 void dfs(int x,int y){ 38 fa1[x]=y; push(x); 39 if (c[x][0]) dfs(c[x][0],y); 40 if (c[x][1]) dfs(c[x][1],y); 41 } 42 43 int main(){ 44 freopen("bzoj2959.in","r",stdin); 45 freopen("bzoj2959.out","w",stdout); 46 scanf("%d%d",&n,&m); 47 rep(i,1,n) scanf("%d",&w[i]),sm[i]=v[i]=w[i],fa1[i]=fa2[i]=i; 48 rep(i,1,m){ 49 scanf("%d%d%d",&op,&x,&y); int tx=get1(x),ty=op==2?0:get1(y); 50 if (op==1){ 51 if (tx==ty) continue; 52 if (get2(tx)!=get2(ty)) link(tx,ty),fa2[get2(tx)]=get2(ty); 53 else split(tx,ty),w[ty]=sm[ty],dfs(ty,ty),c[ty][0]=0; 54 } 55 if (op==2) splay(tx),w[tx]+=y-v[x],sm[tx]+=y-v[x],v[x]=y; 56 if (op==3){ 57 if (get2(tx)!=get2(ty)) puts("-1"); 58 else split(tx,ty),printf("%d\n",sm[ty]); 59 } 60 } 61 return 0; 62 }