• P3690 【模板】Link Cut Tree (动态树)


    人生第一颗动态树
    动态树就是类似树链剖分的利用splay森林维护树上一些链的操作
    因为虚实链可以变化,所以叫做动态树
    然后因为是splay森林,所以判断是否存在g时应当使用isroot(f)而不是g==0
    然后是常规的splay操作
    link和cut时注意判断合法
    上代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    struct SNode{
        int son[2],tag,val,sum;
    }SPT[300100];
    int fa[300100],sta[300100],topc,n,m;
    void pushup(int o){
        SPT[o].sum=SPT[SPT[o].son[0]].sum^SPT[o].val^SPT[SPT[o].son[1]].sum;
    }
    void pushdown(int o){
        if(o&&SPT[o].tag){
            swap(SPT[o].son[0],SPT[o].son[1]);
            SPT[SPT[o].son[0]].tag^=1;
            SPT[SPT[o].son[1]].tag^=1;
            SPT[o].tag=0;
        }
    }
    bool isroot(int o){
        return (SPT[fa[o]].son[0]!=o)&&(SPT[fa[o]].son[1]!=o);
    }
    bool isrl(int o){//true right false left
        return SPT[fa[o]].son[1]==o;
    }
    void rorate(int o){
        if(isroot(o))
            return;
        int f=fa[o];
        int g=fa[f];
        int which=isrl(o);
        pushdown(f);
        pushdown(o);
        fa[o]=g;
        if(!isroot(f))
            SPT[g].son[SPT[g].son[1]==f]=o;
        SPT[f].son[which]=SPT[o].son[which^1];
        fa[SPT[o].son[which^1]]=f;
        SPT[o].son[which^1]=f;
        fa[f]=o;
        pushup(f);
        pushup(o);
    }
    void splay(int o){
        topc=0;
        int y=o;
        sta[++topc]=y;
        while(!isroot(y)){
            sta[++topc]=fa[y];
            y=fa[y];
        }
        for(int i=topc;i>=1;i--)
            pushdown(sta[i]);
        for(int f;!isroot(o);rorate(o)){
            if(!isroot(f=fa[o]))
                rorate((isrl(f)==isrl(o))?f:o);
        }
    }
    void access(int o){
        for(int y=0;o;o=fa[y=o]){
            splay(o),SPT[o].son[1]=y,pushup(o);
        }
    }
    void makeroot(int o){
        access(o);
        splay(o);
        // printf("ok
    ");
        SPT[o].tag^=1;
        pushdown(o);
    }
    int findroot(int o){
        access(o);
        splay(o);
        pushdown(o);
        while(SPT[o].son[0])
            pushdown(o=SPT[o].son[0]);
        return o;
    }
    void split(int x,int y){
        // printf("ok
    ");
        makeroot(x);
        access(y);
        // printf("ok!
    ");
        splay(y);
    }
    void link(int x,int y){//x->y
        makeroot(x);
        if(findroot(y)!=x)
            fa[x]=y;
    }
    void cut(int x,int y){//dep[x]<dep[y]
        makeroot(x);
        if(findroot(y)==x&&fa[x]==y&&SPT[y].son[0]==x&&SPT[x].son[1]==0)
            fa[x]=0,SPT[y].son[0]=0,pushup(y);
    }
    int query(int x,int y){
        split(x,y);
        return SPT[y].sum;
    }
    int main(){
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&SPT[i].val),SPT[i].sum=SPT[i].val;
        for(int i=1;i<=m;i++){
            int opt,x,y;
            scanf("%d %d %d",&opt,&x,&y);
            if(opt==0)
                printf("%d
    ",query(x,y));
            else if(opt==1)
                link(x,y);
            else if(opt==2)
                cut(x,y);
            else
                splay(x),SPT[x].val=y;
        }
        return 0;
    }
    
  • 相关阅读:
    Java精通并发-Lock锁方法原理详解
    Java精通并发-Lock锁机制深入详解
    深层次揭示runBlocking与coroutineScope之间的异同点
    轻量级协程与线程执行比对分析
    第二阶段冲刺个人任务——four
    第二阶段冲刺个人任务——three
    第二阶段冲刺个人任务——two
    第二阶段冲刺个人任务——one
    输入法评价
    2017.12.30第十五周学习进度
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10057103.html
Copyright © 2020-2023  润新知