SPOJ 375 LCT学习

今天把这题的LCT补了一下:


下面是用树链剖分写的,上面使用LCT写的,树链剖分确实比LCT快,据说是LCT多一个常数的关系,但是这道题由于数据比较小的关系吧,树链剖分并没有比LCT快多少。

这道题的关键是一个边权转换成点权来写(话说如果这个不知道,那么树链剖分也写不出来了吧,但是我感觉是不是可以用map<pair<int,int>,int>来直接存边,然后做,好像这个样子又会多一个logn,没有尝试写过。。。),边权转化成点权在树链剖分中写起来很简单,其实LCT写起来也很简单,最主要是要找一个LCA,然后这个点的点权就不需要了,如果把这个点转化成root的话,那么我们需要查询的就是max(maxx[ch[root][0]],maxx[ch[root][1]]),那么我们现在要做的就是一个找LCA的过程,原来开始学LCT的时候是看着bin神代码学的,但是觉得他的LCA好像并没有什么用(果然还是太年轻)。LCA部分是学习bin神的,其实理解起来也比较简单,其实是两个Access过程,先Access(v),这个时候v到根节点的所有点形成了一个SPLAY,这个时候Access(u)这个过程中会找到v到根节点这棵SPLAY树(很容易理解,因为Access过程就是找到根的prefer-path,肯定会与前一个过程重合,说得再直白点,就是根节点一点是u,v的公共节点),然后我们发现这个时候把u转到根节点时,那么pre[u] == 0了,这个时候找到的这个节点就是u,v的LCA,然后什么都解决了!!!其实还有一个点需要注意一下,就是Access过程已经把你需要PushDown的全部都PuhsDown了。

下面附上代码:

#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 11000

using namespace std;

int n;

struct LCT{
    int pre[MAXN],ch[MAXN][2],key[MAXN];
    int maxx[MAXN],flip[MAXN];
    bool rt[MAXN];

    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(rt,true,sizeof(rt));
        key[0] = key[1] = maxx[0] = maxx[1] = -INF;
        FOR(i,2,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(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];
            if(rt[y]){
                PushDown(y); PushDown(x);
                Rotate(x,ch[y][0] == x);
            }
            else{
                PushDown(z); PushDown(y); PushDown(x);
                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);
        }
    }

    int GetRoot(int x){
        Access(x);
        Splay(x);
        while(ch[x][0]) x = ch[x][0];
        return x;
    }

    void MakeRoot(int x){
        Access(x);
        Splay(x);
        Update_Flip(x);
    }

    void Modify(int x,int w){
        Splay(x);
        key[x] = w;
        PushUp(x);
    }
    //LCA的过程,我只能说v = 0作为u的上一个点很关键!!!这个时候更新完了以后,u是原来的u,v的LCA,现在v是原来u->LVA(u,v)的部分,ch[u][1]对应的就是LVA(u,v)-    //>v的部分!!!
    void Lca(int &u,int &v){
        Access(v),v = 0;
        while(u){
            Splay(u);
            if(!pre[u]) return;
            rt[ch[u][1]] = true;
            rt[ch[u][1] = v] = false;
            PushUp(u);
            u = pre[v = u];
        }
    }

    int Query(int u,int v){
        Lca(u,v);
        return max(maxx[v],maxx[ch[u][1]]);
    }

}lct;

struct Edge{
    int u,v;
    int idd,nt,w;
}edge[MAXN<<1];

int head[MAXN],edge_cnt,id[MAXN];

void add_edge(int u,int v,int idd,int w){
    edge[edge_cnt].u = u;
    edge[edge_cnt].v = v;
    edge[edge_cnt].idd = idd;
    edge[edge_cnt].w = w;
    edge[edge_cnt].nt = head[u];
    head[u] = edge_cnt++;
}

void dfs(int u,int fa){
    lct.pre[u] = fa;
    for(int i = head[u];i != -1;i = edge[i].nt){
        int v = edge[i].v;
        if(v == fa) continue;
        lct.key[v] = edge[i].w;
        id[edge[i].idd] = v;
        dfs(v,u);
    }
}

int main(){
    //freopen("test.in","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        memset(head,-1,sizeof(head));
        edge_cnt = 0;
        FOR(i,1,n){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,i,w);
            add_edge(v,u,i,w);
        }
        dfs(1,0);
        lct.Init();
        char op[10];
        while(~scanf("%s",op) && strcmp(op,"DONE")){
            if(!strcmp(op,"CHANGE")){
                int idd,w;
                scanf("%d%d",&idd,&w);
                lct.Modify(id[idd],w);
            }
            else{
                int u,v;
                scanf("%d%d",&u,&v);
                printf("%d\n",lct.Query(u,v));
            }
        }
    }
    return 0;
}


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

posted @ 2015-09-10 23:07  hqwhqwhq  阅读(171)  评论(0编辑  收藏  举报