zoukankan      html  css  js  c++  java
  • 【树】全局平衡二叉树

    全局平衡二叉树

    学习资料:博客1博客2

    注:博客1讲得比较详细,博客2的代码和博客1区别。

    时间复杂度:(mathcal{O(nlogn)})

    但是 常数比较大(但也没有LCT那么大)!虽然树链剖分的时间复杂度是 (mathcal{O(n logn^2)}),但是树链剖分有时会更快。复杂度允许下,能用树剖还是用树剖好。

    作用:

    全局平衡二叉树是静态树,即区别于LCT,建成后,树的形态不变。同树链剖分,可用于树的修改和查询。

    构造:

    跟树剖类似,求出树的重儿子(重链)。

    对于每一根重链(一根,即 从链头到链尾),建一棵平衡二叉树,然后将链头节点的父亲用作二叉树的根父亲。对于每一根轻链,直接保存其父亲为原始父亲。

    在构建平衡二叉树时,以结点的轻儿子子树总和+1的大小作为权重,亦即,以 (siz[u]-siz[son[u]]) 作为节点 (u) 的权重。

    构建时需保留在新树中

    • 所有节点的父亲: (tfa[u])
    • 重节点的左右儿子:(ch[u][0])(ch[u][1])
    • 根据需要,保留节点深度:(dep[u])
    • 根据需要,保留当前节点子树的信息:(val[u]/sum[u]/mi[u]...)

    过程:

    • 处理出 (lsiz)(son)

      int siz[maxn],lsiz[maxn],son[maxn];
      void dfs(int u,int f)
      {
          siz[u]=1;
          for(int i=head[u];i;i=nxt[i])
              if(to[i]!=f){
                  dfs(to[i],u);
                  siz[u]+=siz[to[i]];
                  if(siz[to[i]]>siz[son[u]])son[u]=to[i];
              }
          lsiz[u]=siz[u]-son[u];
      }//处理出lsiz和son
      
    • 建树

      int tfa[maxn],ch[maxn][2],dep[maxn];
      int si[maxn],vsi[maxn],tot;//si存重链节点序列 vsi是重链节点序列权值(即lsiz)前缀和
      bool vis[maxn];
      int update(int u){}//更新节点信息 比如 mi[u]=min(val[u],mi[ch[u][]]);
      int pushup(int u){
          if(!u)return;
          if(getson(u)!=-1)update(u);// 节点u是其父亲的左儿子或右儿子
      }
      int sbuild(int l,int r,int d)//先看build 再看sbuild
      {
          if(l>r)return 0;
          int mid=lower_bound(vsi+l,vsi+r+1,vsi[r]+vsi[l]>>1)-vsi;
          int u=si[mid];dep[u]=d;
          if(ch[u][0]=sbuild(1,mid-1,d+1))tfa[ch[u][0]]=u;
          if(ch[u][1]=sbuild(mid+1,r,d+1))tfa[ch[u][1]]=u;
          update(u);
      }
      int build(int u,int d)
      {
          int pos;
          for(pos=u,tot=0;pos;pot=son[pos]){
              si[++tot]=pos;vsi[tot]=vsi[tot-1]+lsiz[pos];vis[pos]=1;
          }//当前点必是重链头节点 然后保存重链序列
          int rt=sbuild(1,tot,d);//对当前重链建平衡树
          for(pos=u;pos;pos=son[u])
              for(int i=head[pos];i;i=nxt[i])
                  if(!vis[to[i]])//非重儿子 即 新的重链头
                      tfa[build(to[i],dep[pos]+1)]=pos;//当前节点作为 建成的子平衡树的根 的父亲
      }
      
    • 查询

      找到的几个全局平衡树的博客都是luogu动态dp的这个例题,即 查询是对子树的查询,对子树的查询,在建树和更新过程中重要保存好子树信息,查询时直接输出即可。

      而对于链的查询,比如查询链 ((u,v)) 的点权和,或者链 ((u,v)) 的点权最值,则需要 (log)

      找不到相关博客,想到的方法或许不是最优。具体如下:

      • 需要先用 (st) 表 预处理原树(lca) ,用来 (mathcal{O(1)}) 计算两点间距离。设 (pu=u,pv=v)

      • 对于 (u,v) ,同树剖一样,每次处理都是处理 (dep) 较大的节点,然后计算信息后向上处理。

      • 对于当前节点为 (u)(u) 在链上,判断 (tfa[u]) 是否在 链 ((pu,pv)) 上,且设

        [x=(ch[tfa[u]][1]==u)?1:(ch[tfa[u]][0]==u?0:-1) ]

        • (tfa[u]) 在链上,则 (tfa[u])(u) 可能在同一棵或不同一棵平衡树上,即 (x) 是否等于 -1​。

          假如 (x==-1),则需计算 (ch[u][0]) 的子树信息。否则 计算 (ch[u][x)^(1]) 的子树信息。

          再计算 (tfa[u]) 的节点信息

        • (tfa[u]) 不在链上,则 (tfa[u])(u) 必定在同一棵平衡二叉树上。只需计算 (ch[u][x]) 的子树信息。

      • (u=tfa[u])

      具体代码如下:

      inline bool getson(int x){
          return (ch[tfa[x]][1]==x)?1:((ch[tfa[x]][0]==x)?0:-1);
      }
      inline bool online(int u,int v,int po){
          returndis(u,po)+dis(v,po)==dis(u,v);
      }
      //比如计算 链u v之间的最小点权
      int cal(int u,int v)
      {
          int x,pu=u,pv=v;bool juu=1,juv=1,juf;
          int res=min(val[u],val[v]);
          while(u!=v)
          {
              if(dep[u]<dep[v])swap(u,v),swap(juu,juv);
              x=getson(u);
              juf=online(pu,pv,tfa[u]);
              if(!juf&&juu){
                  if(ch[u][x])res=min(res,mi[ch[u][x]]);
              }else if(juf&&juu){
                  if(x==-1)res=min(res,mi[ch[u][0]]);
                  else res=min(res,mi[ch[u][x^1]]);
                  res=min(res,val[tfa[u]])
              }
              u=tfa[u];juu=juf;
          }
          return res;
      }
      


    一道例题的代码(虽然因为常数过大而超时,树剖反而不超时

    hdu6765(2020多校2C)

    //#pragma GCC optimize(2)
    #include<algorithm>
    #include<cstdio>
    #include<ctime>
    #define min(a,b) (a)<(b)?(a):(b) 
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    const int maxn=5e5+5;
    
    char buf[1<<20],*P1=buf,*P2=buf;
    //#define gc() (P1==P2&&(P2=(P1=buf)+fread(buf,1,1<<20,stdin),P1==P2)?EOF:*P1++)
    #define gc() getchar()
    #define TT template<class T>inline
    TT void read(T&x){
        x=0;register char c=gc();register bool f=0;
        while(c<48||c>57){f^=c=='-',c=gc();}
        while(47<c&&c<58)x=(x<<3)+(x<<1)+(c^48),c=gc();
        if(f)x=-x;
    }
    
    int to[maxn<<1],nxt[maxn<<1];
    int head[maxn],ecnt;
    inline void addedge(int u,int v)
    {
        to[++ecnt]=v;nxt[ecnt]=head[u];
        head[u]=ecnt;
    }
    int depth[maxn<<1],id[maxn],rid[maxn<<1],cnt,st[maxn<<1][25];
    void dfs(int u,int f,int d)
    {
        id[u]=++cnt;rid[cnt]=u;depth[cnt]=d;
        for(int i=head[u];i;i=nxt[i])
            if(to[i]!=f){
                dfs(to[i],u,d+1);
                rid[++cnt]=u;depth[cnt]=d;
            }
    }
    int lg[maxn<<1];
    void init()
    {
        lg[0]=-1;
        for(int i=1;i<=cnt;i++)lg[i]=lg[i>>1]+1;
        for(int i=1;i<=cnt;i++)st[i][0]=i;
        for(int j=1;(1<<j)<=cnt;j++)
            for(int i=1;i+(1<<j)-1<=cnt;i++)
                st[i][j]=depth[st[i][j-1]]<depth[st[i+(1<<j-1)][j-1]]?
                         st[i][j-1]:
                         st[i+(1<<j-1)][j-1];
    }
    inline int lca(int u,int v)
    {
        if(id[u]>id[v])swap(u,v);
        int s=id[u],t=id[v],len=lg[t-s+1];
        return depth[st[s][len]]<depth[st[t-(1<<len)+1][len]]?rid[st[s][len]]:rid[st[t-(1<<len)+1][len]];
    }
    inline int dis(int u,int v){
        return depth[id[u]]+depth[id[v]]-(depth[id[lca(u,v)]]<<1);
    }
    
    //gbbt
    int siz[maxn],lsiz[maxn],son[maxn];
    void dfs1(int u,int f)//处理son和lsiz 的信息
    {
        siz[u]=1;
        for(int i=head[u];i;i=nxt[i])
            if(to[i]!=f){
                dfs1(to[i],u);
                siz[u]+=siz[to[i]];
                if(siz[to[i]]>siz[son[u]])son[u]=to[i];
            }
        lsiz[u]=siz[u]-siz[son[u]];
    }
    int col[maxn];
    int tfa[maxn],ch[maxn][2];
    const int N=30;
    unsigned int mi[maxn][N],val[maxn][N];
    inline void update(int u){
        for(int i=0;i<N;i++){
            mi[u][i]=val[col[u]][i];
            if(ch[u][0])mi[u][i]=min(mi[u][i],mi[ch[u][0]][i]);
            if(ch[u][1])mi[u][i]=min(mi[u][i],mi[ch[u][1]][i]);
        }
    }
    inline int getson(int x){return (ch[tfa[x]][1]==x)?1:((ch[tfa[x]][0]==x)?0:-1);}
    void pushup(int u){ 
        update(u);
        if(getson(u)!=-1)pushup(tfa[u]);
    }
    int si[maxn],tot;ll vsi[maxn];
    int dep[maxn];bool vis[maxn];
    int sbuild(int l,int r,int d)
    {
        if(l>r)return 0;
        int mid=lower_bound(vsi+l,vsi+r+1,vsi[r]+vsi[l-1]>>1)-vsi;
        int u=si[mid];dep[u]=d;
        if(ch[u][0]=sbuild(l,mid-1,d+1))tfa[ch[u][0]]=u;
        if(ch[u][1]=sbuild(mid+1,r,d+1))tfa[ch[u][1]]=u;
        update(u);
        return u;
    }
    int build(int u,int d)
    {
        int pos;
        for(pos=u,tot=0;pos;pos=son[pos]){
            si[++tot]=pos;vsi[tot]=vsi[tot-1]+lsiz[pos];
            vis[pos]=1;
        }
        int rt=sbuild(1,tot,d);
        for(pos=u;pos;pos=son[pos])
            for(int i=head[pos];i;i=nxt[i])
                if(!vis[to[i]])
                    tfa[build(to[i],dep[pos]+1)]=pos;
        return rt;
    }
    inline bool online(int u,int v,int po){
        return dis(u,po)+dis(v,po)==dis(u,v);
    }
    unsigned int tmp[N];
    ll cal(int u,int v)
    {
        int x,pu=u,pv=v;bool juu=1,juv=1,fju;
        for(int i=0;i<N;i++)tmp[i]=min(val[col[u]][i],val[col[v]][i]);
        while(u!=v)
        {
            if(dep[u]<dep[v])swap(u,v),swap(juu,juv);//dep u > dep v
            x=getson(u);
            fju=online(pu,pv,tfa[u]);
            if(!fju){
                if(juu&&ch[u][x]){
                    for(int i=0;i<N;i++)
                        tmp[i]=min(tmp[i],mi[ch[u][x]][i]);
                }
            }else{
                if(juu&&x==-1&&ch[u][0]){
                    for(int i=0;i<N;i++)
                        tmp[i]=min(tmp[i],mi[ch[u][0]][i]);
                }
                else if(juu&&x!=-1&&ch[u][x^1]){
                    x^=1;
                    for(int i=0;i<N;i++)
                        tmp[i]=min(tmp[i],mi[ch[u][x]][i]);
                }
                for(int i=0;i<N;i++)
                    tmp[i]=min(tmp[i],val[col[tfa[u]]][i]);
            }
            juu=fju;u=tfa[u];
        }
        ll sum=0;
        for(int i=0;i<N;i++)sum+=tmp[i];
        return sum;
    }
    mt19937 mt(time(0));
    int main()
    {
    //    freopen("C:\Users\admin\Desktop\tmp\1003.in","r",stdin);
    //    freopen("C:\Users\admin\Desktop\tmp\1003out.txt","w",stdout);
        for(int i=0;i<maxn;i++)
            for(int j=0;j<N;j++)val[i][j]=mt();
        int T;
        read(T);
        while(T--)
        {
            int n,m,u,v,rt,lans=0;
            read(n);read(m);
            for(int i=tot=ecnt=cnt=0;i<=n;i++)
                vis[i]=vsi[i]=head[i]=dep[i]=tfa[i]=son[i]=0;
            for(int i=1;i<=n;i++)read(col[i]);
            for(int i=1;i<n;i++)
            {
                read(u);read(v);
                addedge(u,v);addedge(v,u);
            }
            dfs(1,0,0);init();dfs1(1,0);build(1,1);
            int op,x,y;ll sum1,sum2;
            while(m--)
            {
                read(op);read(x);read(y);
                if(op==1){
                    x^=lans;y^=lans;
                    col[x]=y;pushup(x);
                }else if(op==2){
                    read(u);read(v);
                    x^=lans;y^=lans;u^=lans;v^=lans;
                    sum1=cal(x,y);sum2=cal(u,v);
                    if(sum1<sum2)puts("Yes"),lans++;
                    else puts("No");
                }
            }
        }
    }
    
  • 相关阅读:
    nullnullUVa 10066 The Twin Towers(LCS水题)
    代码错误zoj1298Domino Effect
    实现图形Qt学习:三维绘图之OpenGL和Qt的结合
    情况数组zoj2412Farm Irrigation
    nullnulle人事管理系统人事档案变更管理人员合同变更
    判断条件UVa 10192 Vacation(LCS水题)
    查询数量查看表的所有相关列信息
    代码提交省赛啊省赛
    输入声音如何搜索一张发音的图片
    数组字符串uva 10405 Longest Common Subsequence(最长公共子序列)
  • 原文地址:https://www.cnblogs.com/kkkek/p/13455394.html
Copyright © 2011-2022 走看看