zoukankan      html  css  js  c++  java
  • SPOJ OTOCI 动态树 LCT

    SPOJ OTOCI

    裸的动态树问题。

    回顾一下我们对树的认识。

    最初,它是一个连通的无向的无环的图,然后我们发现由一个根出发进行BFS 会出现层次分明的树状图形。

    然后根据树的递归和层次性质,我们得到了很多有趣的算法,比如单源最短路等等。

    如今,我们面对更复杂的问题,给定一个森林,随时更改树的形态,并询问两个节点之间路径上所有点的权值和。

    要求复杂度O(Logn)

    我们把树看作由若干条链构成,每个链用一个splay维护。

    至此,我们对树的认识已经到了一个比较高的水平了。

    关于LCT的详细阐述,参考http://www.cnblogs.com/zinthos/p/3900225.html

    代码并不复杂, 一句话 splay的核心是splay(x) LCT的核心是access(x)

    此处join(x,y)通过对x的翻转实现,splay(x)后,反转x x就由队尾变成队首此时PNT(x)==null, PNT(x)=y就实现了连接(x,y).

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int MaxNode=31000;
    
    int Lch[MaxNode];
    int Rch[MaxNode];
    int Pnt[MaxNode];
    int Data[MaxNode];
    int Sum[MaxNode];
    int Rev[MaxNode];
    int List[MaxNode];
    int Total;
    
    inline bool isRoot(int t){
        return (!Pnt[t]||(Lch[Pnt[t]]!=t&&Rch[Pnt[t]]!=t));
    }
    inline void Update(int cur){
        Sum[cur]=Sum[Lch[cur]]+Sum[Rch[cur]]+Data[cur];
    }
    void Reverse(int cur){
        if (!Rev[cur]) return;
        swap(Lch[cur],Rch[cur]);
        Rev[Lch[cur]]^=1;
        Rev[Rch[cur]]^=1;
        Rev[cur]=0;
    }
    void LeftRotate(int cur){
        if (isRoot(cur)) return;
        int pnt=Pnt[cur],anc=Pnt[pnt];
        Lch[pnt]=Rch[cur];
        if (Rch[cur]) Pnt[Rch[cur]]=pnt;
        Rch[cur]=pnt;
        Pnt[pnt]=cur;
        Pnt[cur]=anc;
        if (anc){
            if (Lch[anc]==pnt) Lch[anc]=cur;
            else if (Rch[anc]==pnt) Rch[anc]=cur;
        }
        Update(pnt);
        Update(cur);
    }
    void RightRotate(int cur){
        if (isRoot(cur)) return;
        int pnt=Pnt[cur],anc=Pnt[pnt];
        Rch[pnt]=Lch[cur];
        if (Lch[cur]) Pnt[Lch[cur]]=pnt;
        Lch[cur]=pnt;
        Pnt[pnt]=cur;
        Pnt[cur]=anc;
        if (anc){
            if (Rch[anc]==pnt) Rch[anc]=cur;
            else if (Lch[anc]==pnt) Lch[anc]=cur;
        }
        Update(pnt);
        Update(cur);
    }
    void Splay(int cur){
        int pnt,anc;
        List[++Total]=cur;
        for (int i=cur;!isRoot(i);i=Pnt[i]) List[++Total]=Pnt[i];
        for (;Total;--Total)
            if (Rev[List[Total]]) Reverse(List[Total]);
        while (!isRoot(cur)){
            pnt=Pnt[cur];
            if (isRoot(pnt)){// 父亲是根结点,做一次旋转
                if (Lch[pnt]==cur) LeftRotate(cur);
                else RightRotate(cur);
            }
            else{
                anc=Pnt[pnt];
                if (Lch[anc]==pnt){
                    if (Lch[pnt]==cur) LeftRotate(pnt),LeftRotate(cur);// 一条线
                    else RightRotate(cur),LeftRotate(cur);// 相反两次
                }
                else{
                    if (Rch[pnt]==cur) RightRotate(pnt),RightRotate(cur);// 一条线
                    else LeftRotate(cur),RightRotate(cur);// 相反两次
                }
            }
        }
    }
    int Expose(int u){
        int v=0;
        for (;u;u=Pnt[u]) Splay(u),Rch[u]=v,v=u,Update(u);
        for (;Lch[v];v=Lch[v]);
        return v;
    }
    void Modify(int x,int d){
        Splay(x);
        Data[x]=d;
        Update(x);
    }
    int Query(int x,int y){
        int rx=Expose(x),ry=Expose(y);
        if (rx==ry){
            for (int u=x,v=0;u;u=Pnt[u]){
                Splay(u);
                if (!Pnt[u]) return Sum[Rch[u]]+Data[u]+Sum[v];
                Rch[u]=v;
                Update(u);
                v=u;
            }
        }
        return -1;
    }
    bool Join(int x,int y){
        int rx=Expose(x),ry=Expose(y);
        if (rx==ry) return false;
        else{
            Splay(x);
            Rch[x]=0;
            Rev[x]=1;
            Pnt[x]=y;
            Update(x);
            return true;
        }
    }
    void Cut(int x){
        if (Pnt[x]){
            Expose(x);
            Pnt[Lch[x]]=0;
            Lch[x]=0;
            Update(x);
        }
    }
    int n,Q;
    
    void init(){
        Total=0;
        memset(Rev,0,sizeof(Rev));
        memset(Pnt,0,sizeof(Pnt));
        memset(Lch,0,sizeof(Lch));
        memset(Rch,0,sizeof(Rch));
        memset(Sum,0,sizeof(Sum));
    }
    char cmd[22];
    int main()
    {
        init();
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%d",&Data[i]);
        scanf("%d",&Q);
        while (Q--){
            int x,y;
            scanf("%s%d%d",cmd,&x,&y);
            if (cmd[0]=='p'){
                Modify(x,y);
            }
            if (cmd[0]=='b'){
                if (Join(x,y)) printf("yes
    ");
                else printf("no
    ");
            }
            if (cmd[0]=='e'){
                int ans=Query(x,y);
                if (ans==-1) printf("impossible
    ");
                else printf("%d
    ",ans);
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    AcWing 157. 树形地铁系统 (hash判断树同构)打卡
    AcWing 156. 矩阵 (哈希二维转一维查询)打卡
    AcWing 144. 最长异或值路径 01字典树打卡
    AcWing 143. 最大异或对 01字典树打卡
    AcWing 142. 前缀统计 字典树打卡
    AcWing 139. 回文子串的最大长度 hash打卡
    AcWing 138. 兔子与兔子 hash打卡
    常用C库函数功能及用法
    编程实现C库函数
    C语言面试题5
  • 原文地址:https://www.cnblogs.com/heisenberg-/p/6591257.html
Copyright © 2011-2022 走看看