【[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)); } } }