• HDU 4010 动态树LCT学习


    入门LCT的题目,这几天把LCT学习了一下,上手真是好难。这是写的LCT的第一道题,改掉了BUG以后交上去,PE,加了一行空格以后就过了,真是太开心了!!!

    写一点刚开始学习的一点感想,等我把题目补完了再来做一个小结。

    刚开始看http://wenku.baidu.com/view/75906f160b4e767f5acfcedb  这篇论文的时候真是感觉好烦,看了好几遍以后感觉写得确实太优秀了!!!

    LCT也可以说是基于树链剖分的数据结构,树链剖分树按照轻重链剖分,而LCT则是任意的(说是任意的其实也是确定的)。树链剖分是把链扔到树上面进行操作(当然点权也一样,其实对于有根树上的边权也就是点权)。做树链剖分是很关键的就是把无根树转化成有根树。所有树链剖分不支持Link,Cut操作。

    LCT除了一个树链剖分,就是一个Splay树来维护一个森林。LCT核心操作是Access(v),即把v点到根的点建一棵Splay树,很难想象这个过程是一个纯暴力过程!!!我们要找对应的u,v的LCA路径的话,只需要Access(u),然后Splay(u),把u点变为根,然后再Access(v),这样子就建立了一个u,v之间的lca的Splay树。Link,Cut操作看代码就都很明白了。

    因为LCT维护的是一个Splay森林,所以我们需要知道每棵树的树根(即当前节点是不是树根),我们用一个rt[MAXN]数组来表示,这是看bin神博客学习的。这个时候需要注意的就是Splay树操作的核心:旋转。除了更新节点之间的链接之外,还需要更新rt数组。当然Access操作也需要更新rt数组。

    下面先把我的代码附上:

    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #define LL long long
    #define INF 0x3fffffff
    #define FOR(i,x,y)  for(int i = x;i < y;i ++)
    #define IFOR(i,x,y) for(int i = x;i > y;i --)
    #define MAXN 330000
    
    using namespace std;
    
    int n,q;
    vector <int> mat[MAXN];
    
    struct LCT{
        int pre[MAXN],ch[MAXN][2],key[MAXN];
        int maxx[MAXN],add[MAXN],flip[MAXN];
        bool rt[MAXN];
    
        void Update_Add(int x,int w){
            if(!x)  return;
            maxx[x] += w;
            add[x] += w;
            key[x] += w;
        }
    
        void Update_Flip(int x){
            if(!x)  return;
            swap(ch[x][0],ch[x][1]);
            flip[x] ^= 1;
        }
    
        void Init(){
            memset(ch,0,sizeof(ch));
            memset(flip,0,sizeof(flip));
            memset(add,0,sizeof(add));
            memset(rt,true,sizeof(rt));
            maxx[0] = -INF;
            FOR(i,1,n+1)    maxx[i] = key[i];
        }
    
        void PushUp(int x){
            maxx[x] = max(max(maxx[ch[x][1]],maxx[ch[x][0]]),key[x]);
        }
    
        void PushDown(int x){
            if(add[x]){
                if(ch[x][0])    Update_Add(ch[x][0],add[x]);
                if(ch[x][1])    Update_Add(ch[x][1],add[x]);
                add[x] = 0;
            }
            if(flip[x]){
                if(ch[x][0])    Update_Flip(ch[x][0]);
                if(ch[x][1])    Update_Flip(ch[x][1]);
                flip[x] = 0;
            }
        }
    
        void Rotate(int x,int kind){
            int y = pre[x];
            PushDown(y);
            PushDown(x);
            ch[y][!kind] = ch[x][kind];
            if(ch[x][kind]) pre[ch[x][kind]] = y;
            if(rt[y]){
                rt[x] = true;
                rt[y] = false;
            }
            else{
                if(ch[pre[y]][1] == y)  ch[pre[y]][1] = x;
                if(ch[pre[y]][0] == y)  ch[pre[y]][0] = x;
            }
            pre[x] = pre[y];
            pre[y] = x;
            ch[x][kind] = y;
            PushUp(y);
        }
    
        void Splay(int x){
            PushDown(x);
            while(!rt[x]){
                int y = pre[x];
                int z = pre[y];
                PushDown(z); PushDown(y); PushDown(x);
                if(rt[y]){
                    Rotate(x,ch[y][0] == x);
                }
                else{
                    int kind = ch[z][0] == y;
                    if(ch[y][kind] == x){
                        Rotate(x,!kind);
                        Rotate(x,kind);
                    }
                    else{
                        Rotate(y,kind);
                        Rotate(x,kind);
                    }
                }
            }
            PushUp(x);
        }
    
        void Access(int x){
            int fa = 0;
            for(;x;x = pre[fa = x]){
                Splay(x);
                rt[ch[x][1]] = true;
                rt[ch[x][1] = fa] = false;
                PushUp(x);
            }
        }
    <span style="white-space:pre">	</span>
        //找到x这棵子树的树根
        int GetRoot(int x){
            Access(x);
            Splay(x);
            while(ch[x][0]) x = ch[x][0];
            return x;
        }
    
       //把x节点变成当前Splay树的树根 
        void MakeRoot(int x){
            Access(x);
            Splay(x);
            Update_Flip(x);
        }
    
        bool Link(int u,int v){
            if(GetRoot(u) == GetRoot(v))    return false;
            MakeRoot(u);
            pre[u] = v;
            Access(u);
            return true;
        }
    
        bool Cut(int u,int v){
            if(u == v || GetRoot(u) != GetRoot(v))    return false;
            MakeRoot(u);
            Access(v);
            Splay(v);
            if(ch[v][0])    pre[ch[v][0]] = pre[v],rt[ch[v][0]] = true;
            pre[v] = 0;
            ch[v][0] = 0;
            PushUp(v);
            return true;
        }
    
        bool Add(int u,int v,int w){
            int t1 = GetRoot(u);
            int t2 = GetRoot(v);
            if(t1 != t2)    return false;
            MakeRoot(u);
            Access(v);
            Splay(v);
            Update_Add(v,w);
            return true;
        }
    
        int Query(int u,int v){
            int t1 = GetRoot(u);
            int t2 = GetRoot(v);
            if(t1 != t2)    return -1;
            MakeRoot(u);
            Access(v);
            Splay(v);
            return maxx[v];
        }
    
    }lct;
    
    void dfs(int u,int fa){
        lct.pre[u] = fa;
        for(int i = 0;i < mat[u].size();i ++){
            int v = mat[u][i];
            if(v == fa) continue;
            dfs(v,u);
        }
    }
    
    int main(){
        //freopen("test.in","r",stdin);
        while(~scanf("%d",&n)){
            FOR(i,1,n+1)    mat[i].clear();
            FOR(i,1,n){
                int u,v;
                scanf("%d%d",&u,&v);
                mat[u].push_back(v);
                mat[v].push_back(u);
            }
            dfs(1,0);
            FOR(i,1,n+1){
                scanf("%d",&lct.key[i]);
            }
            lct.Init();
            scanf("%d",&q);
            while(q--){
                int op;
                scanf("%d",&op);
                if(op == 1){
                    int u,v;
                    scanf("%d%d",&u,&v);
                    if(!lct.Link(u,v))  printf("-1
    ");
                }
                else if(op == 2){
                    int u,v;
                    scanf("%d%d",&u,&v);
                    if(!lct.Cut(u,v))   printf("-1
    ");
                }
                else if(op == 3){
                    int w,u,v;
                    scanf("%d%d%d",&w,&u,&v);
                    if(!lct.Add(u,v,w)) printf("-1
    ");
                }
                else{
                    int u,v;
                    scanf("%d%d",&u,&v);
                    printf("%d
    ",lct.Query(u,v));
                }
            }
            printf("
    ");
        }
        return 0;
    }
    


    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    05Mybatis_入门程序——根据id查询用户
    04Mybatis_搭建Mybatis的开发环境
    03Mybatis_mybatis框架原理——执行流程
    02Mybatis_原生态jdbc编程中的问题总结——从而引生出为什么要用Mybatis
    01Mybatis_课程安排
    21SpringMvc_异步发送表单数据到Bean,并响应JSON文本返回(这篇可能是最重要的一篇了)
    20SpringMvc_结果的转发可共享参数;重定向不能共享参数
    19SpringMvc_在业务控制方法中收集List集合中包含JavaBean参数
    18SpringMvc_在业务控制方法中收集数组参数
    阿里架构师,讲述基于微服务的软件架构模式(附资料)
  • 原文地址:https://www.cnblogs.com/hqwhqwhq/p/4811881.html
Copyright © 2020-2023  润新知