zoukankan      html  css  js  c++  java
  • 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
    ",(ll)(siz[y]-siz[x])*siz[x]);
        }
        }
      return 0;
    }
  • 相关阅读:
    c# 不常用逻辑运算符
    c# 简单日志记录类 log

    最短路径
    A+B
    floyd 算法
    Kruskal 算法
    快排
    顺序表的逆排
    顺序表中多余元素的删除
  • 原文地址:https://www.cnblogs.com/Zinn/p/10140213.html
Copyright © 2011-2022 走看看