您的位置:首页 > 运维架构

BZOJ4530 BJOI 2014 大融合 LCT维护子树信息

2017-12-04 16:52 477 查看

BZOJ4530 大融合

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

题目中要求的负载就是以一条边端点为根的两个子树的大小相乘。而动态加边的操作很容易想到LCT。一般的LCT通过伸展树维护的是一条链上的信息,但这并不意味着不能使用LCT。

开两个数组Size[x]和sz[x],分别表示以x为根的子树的大小、x的虚儿子的Size和。那么有递推式:

Size[x]=Size[ls[x]]+Size[rs[x]]+1+sz[x]

也就是把Size划分为了伸展树里节点的Size之和、虚儿子的Size之和。那么现在的问题在于如何维护sz数组。注意到本题用到的Access操作中,每次向上跳都最多只会将一条实边改为虚边、一条虚边改为实边;Link操作直接是给一个点增加一个虚儿子。所以在这两个操作中维护一下sz即可。

#include<stdio.h>
#include<algorithm>
#define MAXN 200005
#define ll long long
using namespace std;

int N,Q;

int ls[MAXN],rs[MAXN],fa[MAXN],rev[MAXN],Size[MAXN],sz[MAXN];

bool isrt(int x){return ls[fa[x]]!=x&&rs[fa[x]]!=x;}

void Update(int p)
{
Size[p]=Size[ls[p]]+Size[rs[p]]+sz[p]+1;
//Size[p]=Size[rs[p]]+sz[p]+1;
}

void Putdown(int p)
{
if(rev[p]==0)return;
rev[p]=0;rev[ls[p]]^=1;rev[rs[p]]^=1;
swap(ls[p],rs[p]);
}

void Zig(int x)
{
int y=fa[x],z=fa[y];
if(!isrt(y))
{
if(ls[z]==y)ls[z]=x;
else rs[z]=x;
}
fa[x]=z;fa[y]=x;fa[rs[x]]=y;
ls[y]=rs[x];rs[x]=y;
Update(y);Update(x);
}

void Zag(int x)
{
int y=fa[x],z=fa[y];
if(!isrt(y))
{
if(ls[z]==y)ls[z]=x;
else rs[z]=x;
}
fa[x]=z;fa[y]=x;fa[ls[x]]=y;
rs[y]=ls[x];ls[x]=y;
Update(y);Update(x);
}

int
dc5d
s[MAXN],Top;

void Splay(int x)
{
int i,y,z;

s[++Top]=x;
for(i=x;!isrt(i);i=fa[i])s[++Top]=fa[i];
while(Top)Putdown(s[Top--]);

while(!isrt(x))
{
y=fa[x];z=fa[y];
if(isrt(y))
{
if(ls[y]==x)Zig(x);
else Zag(x);
}
else
{
if(ls[z]==y)
{
if(ls[y]==x)Zig(y),Zig(x);
else Zag(x),Zig(x);
}
else
{
if(rs[y]==x)Zag(y),Zag(x);
else Zig(x),Zag(x);
}
}
}
}

void Access(int x)
{
int t=0;
while(x)
{
Splay(x);
sz[x]=sz[x]-Size[t]+Size[rs[x]];
rs[x]=t;
Update(x);
t=x;x=fa[x];
}
}

void SetRt(int x)
{
Access(x);Splay(x);rev[x]^=1;
}

void Link(int x,int y)
{
SetRt(x);SetRt(y);
sz[y]+=Size[x];
Update(y);
Splay(y);
fa[x]=y;
}

int main()
{
int i,x,y;
char op[3];
ll Ans;

scanf("%d%d",&N,&Q);
for(i=1;i<=N;i++)Size[i]=1;

while(Q--)
{
scanf("%s%d%d",op,&x,&y);
if(op[0]=='A')Link(x,y);
else
{
SetRt(x);Access(y);
Ans=sz[y]+1;
SetRt(y);Access(x);
Ans*=(sz[x]+1);
printf("%lld\n",Ans);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: