大融合——LCT维护子树信息
题目
【题目描述】
小强要在 $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)$。
现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的询问。
【输入格式】
第一行包含两个整数 $N,Q$,表示星球的数量和操作的数量。星球从 $1$ 开始编号。
接下来的 $Q$ 行,每行是如下两种格式之一:
``A x y`` 表示在 $x$ 和 $y$ 之间连一条边。保证之前 $x$ 和 $y$ 是不联通的。
``Q x y`` 表示询问 $(x,y)$ 这条边上的负载。保证 $x$ 和 $y$ 之间有一条边。
【输出格式】
对每个查询操作,输出被查询的边的负载。
【样例输入】
8 6
A 2 3
A 3 4
A 3 8
A 8 7
A 6 5
Q 3 8
【样例输出】
6
【数据范围与提示】
对于所有数据,$1 \leq N,Q \leq 100000$。
题解
用树剖维护子树信息的模板题
因为虚树不认儿子,所以单独开一个数组维护以该节点为 father 的虚树的信息。
操作中只有 link access 会修改,pushup 即可
为什么 split 的 y 不翻转就会 wa
代码
1 #include<bits/stdc++.h> 2 #define LL long long 3 #define _(d) while(d(isdigit(ch=getchar()))) 4 using namespace std; 5 int R(){ 6 int x;bool f=1;char ch;_(!)if(ch=='-')f=0;x=ch^48; 7 _()x=(x<<3)+(x<<1)+(ch^48);return f?x:-x;} 8 const int N=1e5+5; 9 int n,m; 10 char ch[5]; 11 class Link_Cut_Tree{ 12 private: 13 #define Ls(x) ch[x][0] 14 #define Rs(x) ch[x][1] 15 int ch[N][2],fa[N],rev[N],q[N]; 16 void pushup(int x){sum[x]=sum[Ls(x)]+sum[Rs(x)]+sz[x]+1;} 17 bool nroot(int x){return Ls(fa[x])==x||Rs(fa[x])==x;} 18 void pushdown(int x){ 19 if(rev[x]){ 20 swap(Ls(x),Rs(x)); 21 rev[Ls(x)]^=1,rev[Rs(x)]^=1; 22 rev[x]=0; 23 } 24 } 25 void rotate(int x){ 26 int y=fa[x],z=fa[y],fl=(Rs(y)==x),w; 27 if(nroot(y))ch[z][Rs(z)==y]=x; 28 ch[y][fl]=(w=ch[x][!fl]),ch[x][!fl]=y; 29 if(w)fa[w]=y;fa[y]=x,fa[x]=z; 30 pushup(y);return;} 31 void splay(int x){ 32 int y=x,top=0,z;q[++top]=y; 33 while(nroot(y))q[++top]=y=fa[y]; 34 while(top)pushdown(q[top--]); 35 while(nroot(x)){ 36 y=fa[x],z=fa[y]; 37 if(nroot(y)) 38 rotate((Ls(y)==x)^(Ls(z)==y)?x:y); 39 rotate(x);} 40 pushup(x);return;} 41 void access(int x){ 42 for(int y=0;x;y=x,x=fa[x]) 43 splay(x),sz[x]+=sum[Rs(x)]-sum[y],Rs(x)=y,pushup(x); 44 } 45 void makeroot(int x){access(x),splay(x),rev[x]^=1;} 46 public: 47 LL sz[N],sum[N]; 48 void split(int x,int y){makeroot(x),makeroot(y);} 49 void link(int u,int v){split(u,v),fa[u]=v,sz[v]+=sum[u],pushup(v);} 50 }T; 51 int main(){ 52 n=R(),m=R(); 53 for(int i=1;i<=n;i++)T.sum[i]=1; 54 for(int i=1,u,v;i<=m;i++){ 55 scanf("%s",ch+1),u=R(),v=R(); 56 if(ch[1]=='A')T.link(u,v); 57 else T.split(u,v),printf("%lld\n",T.sum[u]*(T.sum[v]-T.sum[u])); 58 } 59 return 0; 60 }