bzoj 4530 大融合 —— LCT维护子树信息

题目: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;
}

 

posted @ 2018-12-18 21:41  Zinn  阅读(113)  评论(0编辑  收藏  举报