【[BJOI2014]大融合】LCT维护子树(虚边信息)
LCT维护子树信息的好题~~
luogu传送门:https://www.luogu.org/problemnew/show/P4219
这个方法是从这篇博文里学到的%%%https://blog.csdn.net/neither_nor/article/details/52979425
大概就是多开一个数组维护虚边上的信息(本题是虚边上点的数量)
考虑哪些操作会影响虚边上的信息:——》Access和link
Access时会将原本实边切换成虚边,把原本虚边切换成实边。那么直接信息里减去原本的信息再加上现在的信息就是了
而link操作则相较之比较麻烦解决。主要是如果将y设为虚边x的父亲之后,y的祖先节点们也需要随之更改信息。因此我们在原本只setroot(x)的link基础上添加关于y的操作---> access(y)+splay(y)这样就将y设置成了根节点就不用考虑更新祖先节点的问题了。
而其他的操作实际稍加考虑就会发现不会涉及虚实问题。
再讲这道题,很容易发现就是边左右子树大小相乘就是了,实现用上LCT维护子树。 答案时,setroot(x) access(y) splay(y) 然后答案就是(虚子树节点y+1)*(虚子树节点x+1)
talk is cheap,show me code!
#include<bits/stdc++.h>
using namespace std;
int n,q;
const int maxn = (int) 1e5;
int fa[maxn],ls[maxn],rev[maxn],rs[maxn],trsiz[maxn],flsiz[maxn];
#define zig(x) zigzag(x,1)
#define zag(x) zigzag(x,2)
bool isroot(int x) { return ls[fa[x]]!=x&&rs[fa[x]]!=x; }
void putup(int x)
{ trsiz[x]=trsiz[ls[x]]+trsiz[rs[x]]+flsiz[x]+1; }
void putdowm(int x)
{
if(!rev[x]) return;
swap(ls[x],rs[x]);
rev[ls[x]]^=1; rev[rs[x]]^=1; rev[x]=0;
}
void zigzag(int x,int knd)
{
int y=fa[x],z=fa[y];
if(!isroot(y))
{
if(ls[z]==y) ls[z]=x;
else rs[z]=x;
}
fa[x]=z; fa[y]=x;
if(knd==1)
{
ls[y]=rs[x];
fa[ls[y]]=y;
rs[x]=y;
}
else
{
rs[y]=ls[x];
fa[rs[y]]=y;
ls[x]=y;
}
putup(y); putup(x);
}
void putdowmall(int x)
{
if(!isroot(x)) putdowmall(fa[x]);
putdowm(x);
}
void splay(int x)
{
putdowmall(x);
int y,z;
while(!isroot(x))
{
y=fa[x]; z=fa[y];
if(isroot(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 acc(int x)
{
for(int y=0;x;y=x,x=fa[x])
{
splay(x);
flsiz[x]+=trsiz[rs[x]];
flsiz[x]-=trsiz[y];
rs[x]=y;
}
}
void setroot(int x)
{
acc(x); splay(x); rev[x]^=1;
}
void link(int x,int y)
{
setroot(x); acc(y); splay(y);
fa[x]=y; flsiz[y]+=trsiz[x];
putup(y);
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) trsiz[i]=1;
char ss[5];
int x,y;
for(int i=1;i<=q;i++)
{
scanf("%s%d%d",ss,&x,&y);
if(ss[0]=='A')
{
link(x,y);
}
else
{
setroot(x); acc(y); splay(y);
printf("%d\n",(flsiz[y]+1)*(flsiz[x]+1));
}
}
}

浙公网安备 33010602011771号