BZOJ_4530_[Bjoi2014]大融合_LCT
Description
小强要在N个孤立的星球上建立起一套通信系统。这套通信系统就是连接N个点的一个树。
这个树的边是一条一条添加上去的。在某个时刻,一条边的负载就是它所在的当前能够
联通的树上路过它的简单路径的数量。
![](https://www.lydsy.com/JudgeOnline/upload/201604/ff.png)
例如,在上图中,现在一共有了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]));
}
}
}