题目描述
- 小强要在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)。现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的询问。解析:
看到加边的操作,就能确定是用LCT维护了。但是splay在旋转的过程中,与之相连的儿子有时会被丢掉。这是我们可以考虑另开一个数组来维护那些在LCT上与之相连但splay上分开的儿子节点,然后就完了。要注意的是维护LCT上的节点的操作正好与Splay相反,这样才能保证一个节点的子数个数的不重不漏。
#include<iostream>
#include<cstdio>
#define M 100010
using namespace std;
int n,q;
int f[M],size[M],ch[M][2],rev[M],si[M];
void update(int x)
{
size[x]=size[ch[x][0]]+size[ch[x][1]]+si[x]+1;
}
void pushdown(int x)
{
if(rev[x]&&x)
{
if(ch[x][0]) rev[ch[x][0]]^=1;
if(ch[x][1]) rev[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
rev[x]^=1;
}
}
int is_root(int x)
{
return ch[f[x]][0]!=x&&ch[f[x]][1]!=x;
}
int get_son(int x)
{
return ch[f[x]][1]==x;
}
void rotate(int x)
{
int old=f[x],oldf=f[old],k=get_son(x);
if(!is_root(old)) ch[oldf][ch[oldf][1]==old]=x;
ch[old][k]=ch[x][k^1];
f[ch[old][k]]=old;
ch[x][k^1]=old;
f[old]=x;
f[x]=oldf;
update(old);
update(x);
}
void push(int x)
{
if(!is_root(x)) push(f[x]);
pushdown(x);
}
void splay(int x)
{
push(x);
for(int fa;!is_root(x);rotate(x))
if(!is_root(fa=f[x]))
rotate(get_son(x)==get_son(fa)?fa:x);
}
void access(int x)
{
for(int y=0;x;y=x,x=f[x])
{
splay(x);
si[x]+=size[ch[x][1]];
ch[x][1]=y;
si[x]-=size[ch[x][1]];
}
}
void makeroot(int x)
{
access(x);
splay(x);
rev[x]^=1;
}
void link(int x,int y)
{
makeroot(x);
access(y);
splay(y);
f[x]=y;
si[f[x]]+=size[x];
update(y);
}
int query(int x,int y)
{
makeroot(x);
access(y);
splay(y);
return (size[y]-size[x])*size[x];
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) size[i]=1;
for(int i=1;i<=q;i++)
{
char opt;
int x,y;
cin>>opt;
scanf("%d%d",&x,&y);
if(opt=='A') link(x,y);
else printf("%d\n",query(x,y));
}
return 0;
}