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

 

posted @ 2018-08-04 11:12  bztMinamoto  阅读(188)  评论(0编辑  收藏  举报
Live2D