BZOJ 2959 长跑 (LCT+并查集)

题面:BZOJ传送门

当成有向边做的发现过不去样例,改成无向边就忘了原来的思路..

因为成环的点一定都能取到,我们把它们压成一个新点,权值为环上所有点的权值和

这样保证了图是一颗森林

每次询问转化为,取出$a$到$b$这条链,求链上所有点的权值和

这实际是一个不删边的动态维护边双的过程

可以用$LCT$维护

加入一条边$<x,y>$时,我们取出链$x,y$

如果$x,y$原来不连通,把它们连上

否则说明$x,y$原来就联通的,连上这条边会成环,把$x,y$这条链上的点全都压成一个点,用并查集维护

每次$access$都在并查集里找父亲就行了

维护权值的时候细节比较多

  1 #include <vector>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define N1 150010
  6 #define M1 (N1<<1)
  7 #define il inline
  8 #define idx(X) (X-'a')
  9 using namespace std;
 10  
 11 char str[M1];
 12 int n,m,de;
 13 int a[N1],r[N1];
 14  
 15 struct Union{
 16 int fa[N1];
 17 int findfa(int x)
 18 {
 19     int pre,y=x; 
 20     if(!x) return 0;
 21     while(fa[y]!=y) y=fa[y]; 
 22     while(fa[x]!=y){ pre=fa[x]; fa[x]=y; x=pre; }
 23     return y;
 24 }
 25 }U;
 26 struct LCT{
 27 int ch[N1][2],fa[N1],rev[N1],sum[N1],stk[N1],tp;
 28 il int idf(int x){ return (ch[fa[x]][0]==x)?0:1;}
 29 il void pushup(int x){ sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+a[x]; }
 30 il int isroot(int x){ return (ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x)?1:0; }
 31 il void revers(int x){ swap(ch[x][0],ch[x][1]),rev[x]^=1; }
 32 il void pushdown(int x)
 33 { 
 34     if(rev[x])  
 35     {
 36         if(ch[x][0]) revers(ch[x][0]);
 37         if(ch[x][1]) revers(ch[x][1]);
 38         rev[x]^=1;
 39     }
 40 }
 41 il void rot(int x)
 42 {
 43     int y=fa[x],ff=fa[y],px=idf(x),py=idf(y);
 44     if(!isroot(y)) ch[ff][py]=x; fa[x]=ff;
 45     fa[ch[x][px^1]]=y; ch[y][px]=ch[x][px^1];
 46     fa[y]=x; ch[x][px^1]=y;
 47     pushup(y),pushup(x);
 48 }
 49 void splay(int x)
 50 {
 51     int y=x; stk[++tp]=x;
 52     while(!isroot(y)){stk[++tp]=fa[y],y=fa[y];}
 53     while(tp){pushdown(stk[tp--]);}
 54     while(!isroot(x))
 55     {
 56         y=fa[x];
 57         if(isroot(y)) rot(x);
 58         else if(idf(y)==idf(x)) rot(y),rot(x);
 59         else rot(x),rot(x);
 60     }
 61 }
 62 void access(int x)
 63 {
 64     for(int y=0;x;y=x,fa[x]=U.findfa(fa[x]),x=fa[x])
 65         splay(x),ch[x][1]=y,pushup(x);
 66 }
 67 void mkroot(int x)
 68 {
 69     access(x);
 70     splay(x);
 71     revers(x);
 72 }
 73 int findroot(int x)
 74 {
 75     access(x); splay(x);
 76     while(ch[x][0]) pushdown(ch[x][0]),x=ch[x][0];
 77     splay(x); return x;
 78 }
 79 void split(int x,int y)
 80 {
 81     mkroot(x); 
 82     access(y);
 83     splay(y);
 84 }
 85 void dfs(int x,int root)
 86 {
 87     U.fa[x]=root; 
 88     if(ch[x][0]) dfs(ch[x][0],root);
 89     if(ch[x][1]) dfs(ch[x][1],root);
 90 }
 91 int link(int x,int y)
 92 {
 93     /*if(x==4&&y==1)
 94         de=1; */
 95     mkroot(x); access(y); splay(y);
 96     int f=findroot(y);
 97     if(f==x){ //merge
 98         dfs(f,f); a[f]=sum[f];
 99         ch[f][0]=ch[f][1]=0;
100     }else{ //link
101         fa[x]=y;
102     }
103 }
104 int query(int x,int y)
105 {
106     split(x,y);
107     if(findroot(y)!=x) return -1;
108     else return sum[x];
109 }
110 }lct;
111  
112  
113 int main()
114 {
115     scanf("%d%d",&n,&m);
116     int i,j,A,B,x,y,v,fl,ans=0,id=0,de;
117     for(i=1;i<=n;i++) 
118         scanf("%d",&a[i]), lct.sum[i]=a[i], r[i]=a[i], U.fa[i]=i;
119     while(m--)
120     {
121         scanf("%d%d%d",&fl,&A,&B);
122         if(fl==1)
123         { 
124             x=U.findfa(A); y=U.findfa(B);
125             lct.link(x,y); 
126         }
127         if(fl==2)
128         { 
129             x=U.findfa(A); lct.splay(x);
130             lct.sum[x]+=B-r[A]; 
131             a[x]+=B-r[A];
132             r[A]=B;
133         }
134         if(fl==3)
135         {
136             x=U.findfa(A); y=U.findfa(B);  
137             printf("%d
",lct.query(x,y));
138         }
139     }
140     return 0;
141 }
原文地址:https://www.cnblogs.com/guapisolo/p/10326209.html