小强要在 $N$ 个孤立的星球上建立起一套通信系统。这套通信系统就是连接 $N$ 个点的一个树。这个树的边是一条一条添加上去的。在某个时刻,一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量。
例如,在上图中,现在一共有五条边。其中,$(3,8)$ 这条边的负载是 $6$,因为有六条简单路径 $2-3-8, 2-3-8-7, 3-8, 3-8-7, 4-3-8, 4-3-8-7$ 路过了 $(3,8)$。
现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的询问。
Solution
题目求的是一条边两侧子树大小之积。支持插边。
那么可以考虑lct。
有个问题:lct不能维护子树信息。
那么我们可以对于一个点,把实儿子和虚儿子分开维护,还有一个总的信息。
总信息=实儿子的总信息+虚儿子的信息+本身的信息。
要改的只有link和access。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 #define maxn 100005 8 using namespace std; 9 int n,q,t1,t2; 10 struct node{ 11 int f,ch[2],sum,sx,sy;//sum ×ÜºÍ sx ʵ×ÓÊ÷ sy Ðé×ÓÊ÷ 12 int re; 13 }tr[maxn]; 14 void wh(int x){ 15 int ls=tr[x].ch[0],rs=tr[x].ch[1]; 16 tr[x].sum=tr[ls].sum+tr[rs].sum+tr[x].sy+1; 17 } 18 int zh[maxn],top; 19 void upv(int x){ 20 if(!x)return; 21 tr[x].re^=1; 22 swap(tr[x].ch[0],tr[x].ch[1]); 23 } 24 void down(int x){ 25 if(tr[x].re){ 26 upv(tr[x].ch[0]);upv(tr[x].ch[1]); 27 tr[x].re=0; 28 } 29 } 30 int get(int x){ 31 return tr[tr[x].f].ch[1]==x; 32 } 33 bool isroot(int x){ 34 return tr[tr[x].f].ch[0]!=x&&tr[tr[x].f].ch[1]!=x; 35 } 36 37 void rotate(int x){ 38 int y=tr[x].f,z=tr[y].f; 39 int wx=get(x),wy=get(y); 40 if(!isroot(y))tr[z].ch[wy]=x;tr[x].f=z; 41 tr[y].ch[wx]=tr[x].ch[wx^1];tr[tr[x].ch[wx^1]].f=y; 42 tr[x].ch[wx^1]=y;tr[y].f=x; 43 wh(y);wh(x); 44 } 45 void splay(int x){ 46 int y=x;top=0; 47 for(;!isroot(y);y=tr[y].f)zh[++top]=y;zh[++top]=y; 48 while(top)down(zh[top--]); 49 while(!isroot(x)){ 50 y=tr[x].f; 51 if(!isroot(y))rotate(get(y)==get(x)?y:x); 52 rotate(x); 53 } 54 } 55 void access(int x){ 56 for(int y=0;x;y=x,x=tr[x].f){ 57 splay(x); 58 tr[x].sy+=tr[tr[x].ch[1]].sum; 59 tr[x].ch[1]=y; 60 tr[x].sy-=tr[y].sum; 61 wh(x); 62 } 63 } 64 void makeroot(int x){ 65 access(x);splay(x); 66 upv(x);wh(x); 67 } 68 void link(int x,int y){ 69 makeroot(x);makeroot(y); 70 tr[x].f=y; 71 tr[y].sy+=tr[x].sum;wh(y); 72 } 73 void split(int x,int y){ 74 makeroot(x); 75 access(y);splay(y); 76 } 77 long long ask(int x,int y){ 78 split(x,y); 79 int s1=tr[x].sum,s2=tr[y].sum-s1; 80 81 return 1LL*s1*s2; 82 } 83 int main() 84 { 85 cin>>n>>q; 86 for(int i=1;i<=n;i++)tr[i].sum=1; 87 while(q--){ 88 char ch;scanf(" %c",&ch); 89 scanf("%d%d",&t1,&t2); 90 if(ch=='A')link(t1,t2); 91 else printf("%lld ",ask(t1,t2)); 92 } 93 return 0; 94 }