BZOJ_4530_[Bjoi2014]大融合_LCT
BZOJ_4530_[Bjoi2014]大融合_LCT
Description
小强要在N个孤立的星球上建立起一套通信系统。这套通信系统就是连接N个点的一个树。
这个树的边是一条一条添加上去的。在某个时刻,一条边的负载就是它所在的当前能够
联通的树上路过它的简单路径的数量。
例如,在上图中,现在一共有了5条边。其中,(3,8)这条边的负载是6,因
为有六条简单路径2-3-8,2-3-8-7,3-8,3-8-7,4-3-8,4-3-8-7路过了(3,8)。
现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的
询问。
Input
第一行包含两个整数N,Q,表示星球的数量和操作的数量。星球从1开始编号。
接下来的Q行,每行是如下两种格式之一:
A x y 表示在x和y之间连一条边。保证之前x和y是不联通的。
Q x y 表示询问(x,y)这条边上的负载。保证x和y之间有一条边。
1≤N,Q≤100000
Output
对每个查询操作,输出被查询的边的负载。
Sample Input
8 6
A 2 3
A 3 4
A 3 8
A 8 7
A 6 5
Q 3 8
A 2 3
A 3 4
A 3 8
A 8 7
A 6 5
Q 3 8
Sample Output
6
我们都知道正常LCT维护的是一些链的信息。
splay的根不一定连向树上的儿子,这样丢失了儿子的信息。因此无法维护子树信息。
需要在一些操作中加入对子树信息的变动。
设all[x]为x子树结点个数,siz[x]为x子树不在链上结点个数。
注意到access操作割掉了rs加入了t,因此不在链上结点个数需要加rs减去t。
然后link操作也改变了子树信息,需要对两个结点分别更新,makeroot两次即可。
上传函数也改一下。
代码:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define N 100050 #define ls ch[p][0] #define rs ch[p][1] #define get(x) (ch[f[x]][1]==x) int ch[N][2],f[N],rev[N],siz[N],all[N],n,m; char opt[10]; inline bool isrt(int p) { return ch[f[p]][0]!=p&&ch[f[p]][1]!=p; } inline void pushdown(int p) { if(rev[p]) { swap(ch[ls][0],ch[ls][1]); swap(ch[rs][0],ch[rs][1]); rev[ls]^=1; rev[rs]^=1; rev[p]=0; } } inline void pushup(int p) { all[p]=all[ls]+all[rs]+siz[p]+1; } void update(int p) { if(!isrt(p)) update(f[p]); pushdown(p); } void rotate(int x) { int y=f[x],z=f[y],k=get(x); if(!isrt(y)) ch[z][ch[z][1]==y]=x; ch[y][k]=ch[x][!k]; f[ch[y][k]]=y; ch[x][!k]=y; f[y]=x; f[x]=z; pushup(y); pushup(x); } void splay(int x) { update(x); for(int fa;fa=f[x],!isrt(x);rotate(x)) if(!isrt(fa)) rotate(get(fa)==get(x)?fa:x); } void access(int p) { int t=0; while(p) splay(p),siz[p]+=all[rs]-all[t],rs=t,pushup(p),t=p,p=f[p]; } void makeroot(int p) { access(p); splay(p); swap(ls,rs); rev[p]^=1; } void link(int x,int p) { makeroot(x); makeroot(p); f[x]=p; siz[p]+=all[x]; pushup(p); } int main() { scanf("%d%d",&n,&m); int i,x,y; for(i=1;i<=n;i++) all[i]=1; for(i=1;i<=m;i++) { scanf("%s%d%d",opt,&x,&y); if(opt[0]=='A') { link(x,y); }else { makeroot(x); makeroot(y); printf("%lld\n",1ll*all[x]*(all[y]-all[x])); } } }