SPOJ 375 LCT学习

来源:互联网 发布:淘宝卡洛驰官方旗舰店 编辑:程序博客网 时间:2024/05/22 04:50

今天把这题的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 11000using 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;}


0 0
原创粉丝点击