[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 }

 

posted @ 2019-04-02 11:06  HocRiser  阅读(240)  评论(0编辑  收藏  举报