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 
#include 
#include 
#include 
#include 
#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  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);
        }
    }
	
    //找到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\n");
            }
            else if(op == 2){
                int u,v;
                scanf("%d%d",&u,&v);
                if(!lct.Cut(u,v))   printf("-1\n");
            }
            else if(op == 3){
                int w,u,v;
                scanf("%d%d%d",&w,&u,&v);
                if(!lct.Add(u,v,w)) printf("-1\n");
            }
            else{
                int u,v;
                scanf("%d%d",&u,&v);
                printf("%d\n",lct.Query(u,v));
            }
        }
        printf("\n");
    }
    return 0;
}


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

转载于:https://www.cnblogs.com/hqwhqwhq/p/4811881.html

你可能感兴趣的:(HDU 4010 动态树LCT学习)