[BZOJ4530][Bjoi2014]大融合(LCT)
大佬们似乎都是用树剖+并查集优雅地A了此题
然后我太弱了,只能打打LCT的板子
虽然的确可以挺无脑的A掉……
不过至少这题教了我该怎么维护LCT上虚子树的信息,具体看这里
首先,答案很明显是断开边后两个子树的大小之积
所以只要把这条边split出来,答案就是$(size[y]-size[x])*size[x]$(很好理解)
或者$x的虚子树大小*y的虚子树大小$(我用的是这种方法,为什么的话,代码里有注解)
1 //minamoto 2 #include<cstdio> 3 #include<algorithm> 4 #include<iostream> 5 #define ll long long 6 using namespace std; 7 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 8 char buf[1<<21],*p1=buf,*p2=buf; 9 inline int read(){ 10 #define num ch-'0' 11 char ch;bool flag=0;int res; 12 while(!isdigit(ch=getc())) 13 (ch=='-')&&(flag=true); 14 for(res=num;isdigit(ch=getc());res=res*10+num); 15 (flag)&&(res=-res); 16 #undef num 17 return res; 18 } 19 char obuf[1<<24],*o=obuf; 20 inline void print(ll x){ 21 if(x>9) print(x/10); 22 *o++=x%10+48; 23 } 24 const int N=100005; 25 int fa[N],ch[N][2],s[N],rev[N],top,sum[N],summ[N]; 26 inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;} 27 inline void pushup(int x){sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+summ[x]+1;} 28 inline void pushdown(int x){ 29 if(x&&rev[x]){ 30 swap(ch[x][0],ch[x][1]); 31 rev[ch[x][0]]^=1,rev[ch[x][1]]^=1; 32 rev[x]=0; 33 } 34 } 35 void rotate(int x){ 36 int y=fa[x],z=fa[y],d=ch[y][1]==x; 37 if(!isroot(y)) ch[z][ch[z][1]==y]=x; 38 fa[x]=z,fa[y]=x,fa[ch[x][d^1]]=y,ch[y][d]=ch[x][d^1],ch[x][d^1]=y,pushup(y); 39 } 40 void splay(int x){ 41 s[top=1]=x;for(int i=x;!isroot(i);i=fa[i]) s[++top]=fa[i]; 42 while(top) pushdown(s[top--]); 43 for(int y=fa[x],z=fa[y];!isroot(x);y=fa[x],z=fa[y]){ 44 if(!isroot(y)) 45 ((ch[y][1]==x)^(ch[z][1]==y))?rotate(x):rotate(y); 46 rotate(x); 47 } 48 pushup(x); 49 } 50 inline void access(int x){ 51 for(int y=0;x;x=fa[y=x]) 52 splay(x),summ[x]+=sum[ch[x][1]],summ[x]-=sum[ch[x][1]=y]; 53 } 54 inline void makeroot(int x){ 55 access(x),splay(x),rev[x]^=1; 56 } 57 inline void split(int x,int y){ 58 makeroot(x),access(y),splay(y); 59 } 60 inline void link(int x,int y){ 61 split(x,y),summ[fa[x]=y]+=sum[x],pushup(y); 62 } 63 int main(){ 64 //freopen("testdata.in","r",stdin); 65 int n=read(),m=read(); 66 for(int i=1;i<=n;++i) sum[i]=1; 67 while(m--){ 68 char ch;int u,v; 69 ch=getc(),u=read(),v=read(); 70 if(ch=='A') link(u,v); 71 else split(u,v),print(1ll*(summ[u]+1)*(summ[v]+1)),*o++='\n'; 72 /*split之后splay中肯定只有u,v两点 73 然后虚子树中的点数就相当于cut之后两点各自的子树大小 74 然后又因为u和v都已经被splay过了,肯定没有点在它上面*/ 75 } 76 fwrite(obuf,o-obuf,1,stdout); 77 return 0; 78 }
深深地明白自己的弱小