• 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
    ",lct.Query(u,v));
                }
            }
        }
        return 0;
    }
    


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

  • 相关阅读:
    async await 死锁简单分析
    如何在Linux上安装Git Server
    Winform业务层如何调用UI层的代码
    Git是怎么Ignore文件的?
    使用委托把方法写得更容易维护
    我们检测到您的浏览器不兼容传输层安全协议 (TLS) 1.1 或更高版本,此协议在 Internet 上用于确保您通信的安全性。
    【腾讯bugly干货】QQ空间直播秒开优化实践
    【腾讯bugly干货分享】Android自绘动画实现与优化实战——以Tencent OS录音机波形动
    【腾许Bugly干货分享】“HTTPS”安全在哪里?
    【腾讯优测干货】看腾讯的技术大牛如何将Crash率从2.2%降至0.2%?
  • 原文地址:https://www.cnblogs.com/hqwhqwhq/p/4811880.html
Copyright © 2020-2023  润新知