1. 程式人生 > >bzoj 4530 [Bjoi2014]大融合——LCT維護子樹資訊

bzoj 4530 [Bjoi2014]大融合——LCT維護子樹資訊

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

LCT維護子樹 siz 。設 sm[ ] 表示輕兒子的 siz 和+1(1是自己的siz),siz[ ] 表示 splay 裡 ( 兩個兒子的 siz[ ] ) + sm[ cr ] 。在 access 裡隨便維護一下就好了。

一開始寫的 siz[ ]  是 splay 裡右兒子的 siz[ ] + sm[ cr ] ,但打 rev[ ]  的時候難以維護,所以棄了。

注意要先讓一個點作為 splay 的根,再給它連右兒子,才能比較好地維護好;所以 link( ) 的時候注意 access( y ) !

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=1e5+5;
int n,Q,fa[N],c[N][2],siz[N],sm[N];
int sta[N],top;bool rev[N];
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  
while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;} void pshp(int x){siz[x]=sm[x]+siz[c[x][0]]+siz[c[x][1]];} void Rev(int x) { if(!rev[x])return;rev[x]=0; rev[c[x][0]]^=1;rev[c[x][1]]^=1; swap(c[x][
0],c[x][1]); } void rotate(int x) { int y=fa[x],z=fa[y],d=(x==c[y][1]); if(!isroot(y))c[z][y==c[z][1]]=x; fa[x]=z; fa[y]=x;fa[c[x][!d]]=y; c[y][d]=c[x][!d];c[x][!d]=y; pshp(y);pshp(x); } void splay(int x) { sta[top=1]=x; for(int k=x;!isroot(k);k=fa[k])sta[++top]=fa[k]; for(int i=top;i;i--)Rev(sta[i]); int y,z; while(!isroot(x)) { y=fa[x];z=fa[y]; if(!isroot(y)) ((x==c[y][0])^(y==c[z][0]))?rotate(x):rotate(y); rotate(x); } } void access(int x) { int t=0; while(x) { splay(x); sm[x]+=siz[c[x][1]]; sm[x]-=siz[t]; c[x][1]=t; pshp(x);///// t=x;x=fa[x]; } } void makeroot(int x) { access(x);splay(x);rev[x]^=1; } void link(int x,int y) { makeroot(x);access(y);splay(y);//access()!!! fa[x]=y;sm[y]+=siz[x];siz[y]+=siz[x]; } ll query(int x,int y) { makeroot(x);access(y);splay(y); return (ll)siz[x]*sm[y]; } int main() { n=rdn();Q=rdn(); for(int i=1;i<=n;i++)siz[i]=1,sm[i]=1; int x,y;char ch[3]; while(Q--) { scanf("%s",ch);x=rdn();y=rdn(); if(ch[0]=='A')link(x,y); else printf("%lld\n",query(x,y)); } return 0; }