1. 程式人生 > >bzoj 4530 大融合 —— LCT維護子樹信息

bzoj 4530 大融合 —— LCT維護子樹信息

void tar urn rev ESS print algo pan pro

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=4530

用LCT維護子樹 size,就是實邊和虛邊分開維護;

看博客:https://blog.csdn.net/neither_nor/article/details/52979425

代碼如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const xn=1e5+5;
int n,fa[xn],siz[xn],lt[xn],c[xn][2
],sta[xn],top,rev[xn]; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<0||ch>9){if(ch==-)f=0; ch=getchar();} while(ch>=0&&ch<=9)ret=ret*10+ch-0,ch=getchar(); return f?ret:-ret; } bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;} void pushup(int
x){siz[x]=lt[x]+siz[c[x][0]]+siz[c[x][1]]+1;}// void rotate(int x) { int y=fa[x],z=fa[y],d=(c[y][1]==x); if(!isroot(y))c[z][c[z][1]==y]=x; fa[x]=z; fa[y]=x; fa[c[x][!d]]=y; c[y][d]=c[x][!d]; c[x][!d]=y; pushup(y); pushup(x); } void rever(int x){rev[x]^=1; swap(c[x][0],c[x][1]);} void psd(int x) {
if(!rev[x])return; rever(c[x][0]); rever(c[x][1]); rev[x]=0; } void splay(int x) { sta[top=1]=x; for(int i=x;!isroot(i);i=fa[i])sta[++top]=fa[i]; while(top)psd(sta[top--]); while(!isroot(x)) { int y=fa[x],z=fa[y]; if(!isroot(y)) ((c[y][0]==x)^(c[z][0]==y))?rotate(x):rotate(y); rotate(x); } } void access(int x) { for(int t=0;x;t=x,x=fa[x]) { splay(x); //if(c[x][1])siz[x]-=siz[c[x][1]],lt[x]+=siz[c[x][1]]; if(c[x][1])lt[x]+=siz[c[x][1]]; c[x][1]=t; //if(t)siz[x]+=siz[t],lt[x]-=siz[t]; if(t)lt[x]-=siz[t]; pushup(x); } } void makeroot(int x) { access(x); splay(x); rever(x); } void link(int x,int y) { makeroot(x); access(y); splay(y); fa[x]=y; lt[y]+=siz[x]; pushup(y); } char dc[3]; int main() { n=rd(); int m=rd(); for(int i=1,x,y;i<=m;i++) { scanf("%s",dc); x=rd(); y=rd(); if(dc[0]==A)link(x,y); else { makeroot(x); access(y); splay(y); printf("%lld\n",(ll)(siz[y]-siz[x])*siz[x]); } } return 0; }

bzoj 4530 大融合 —— LCT維護子樹信息