1. 程式人生 > >[LOJ2230][BJOI2014]大融合

[LOJ2230][BJOI2014]大融合

sum int splay 可見 void -s problem loj 更新

題面戳我

sol

LCT維護子樹size。
開一個數組\(sz_i\)表示一個節點的所有虛兒子的size和,\(sum_i\)表示以一個節點為根的子樹的\(size\)和,可見\(sz_u=\sum_{v\mbox{是}u\mbox{的虛兒子}}sum_v\)
那麽我們就需要動態維護這兩個東西,首先考慮\(sz_i\),這個只有在兒子的虛實關系被修改的時候才會變化,所以只有\(access\)\(link\)的時候會改變。在\(access\)中一定會是一個兒子由虛變實,一個兒子由實變虛。因為維護的是虛兒子的和,所以加上那個由實變虛的,減去那個由虛變實的。
\(link\)裏面註意兩個點都要\(makeroot\)

一下,然後\(sz\)也要更新,因為\(link\)連接了以後是默認虛兒子。
\(sum_i\)就有一個遞推式直接\(pushup\)就好了。
\[sum_x=sum_{ls_x}+sum_{rs_x}+1+sz_x\]

code

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 200005;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-'
) ch=getchar(); if (ch=='-') w=0,ch=getchar(); while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } int n,q,fa[N],ls[N],rs[N],rev[N],sz[N],sum[N],Stack[N],top; char s[1000]; bool isroot(int x){return ls[fa[x]]!=x&&rs[fa[x]]!=x;} void
pushup(int x){sum[x]=sum[ls[x]]+sum[rs[x]]+1+sz[x];} void reverse(int x){swap(ls[x],rs[x]);rev[x]^=1;} void pushdown(int x){if(!rev[x])return;if(ls[x])reverse(ls[x]);if(rs[x])reverse(rs[x]);rev[x]=0;} void R_rotate(int x) { int y=fa[x],z=fa[y]; ls[y]=rs[x]; if (rs[x]) fa[rs[x]]=y; fa[x]=z; if (y==ls[z]) ls[z]=x;if (y==rs[z]) rs[z]=x; rs[x]=y;fa[y]=x; pushup(y); } void L_rotate(int x) { int y=fa[x],z=fa[y]; rs[y]=ls[x]; if (ls[x]) fa[ls[x]]=y; fa[x]=z; if (y==ls[z]) ls[z]=x;if (y==rs[z]) rs[z]=x; ls[x]=y;fa[y]=x; pushup(y); } void splay(int x) { Stack[top=1]=x; for (int i=x;!isroot(i);i=fa[i]) Stack[++top]=fa[i]; while (top) pushdown(Stack[top--]); while (!isroot(x)) { int y=fa[x],z=fa[y]; if (isroot(y)) if (x==ls[y]) R_rotate(x); else L_rotate(x); else if (y==ls[z]) if (x==ls[y]) R_rotate(y),R_rotate(x); else L_rotate(x),R_rotate(x); else if (x==ls[y]) R_rotate(x),L_rotate(x); else L_rotate(y),L_rotate(x); } pushup(x); } void access(int x){for (int y=0;x;y=x,x=fa[x]) splay(x),sz[x]+=sum[rs[x]]-sum[y],rs[x]=y,pushup(x);} void makeroot(int x){access(x);splay(x);reverse(x);} void split(int x,int y){makeroot(x);access(y);splay(y);} void link(int x,int y){makeroot(x);makeroot(y);fa[x]=y;sz[y]+=sum[x];pushup(y);} int main() { n=gi();q=gi(); for (int i=1;i<=n;i++) sum[i]=1; while (q--) { scanf("%s",s);int u=gi(),v=gi(); if (s[0]=='A') link(u,v); else split(u,v),printf("%lld\n",1ll*sum[u]*(sum[v]-sum[u])); } return 0; }

[LOJ2230][BJOI2014]大融合