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


    阅读前请确保你会( ext{splay})
    ( ext{LinkCutTree})模板,简称( ext{lct})
    首先我们把一棵树里所有节点都全部划分在一些( ext{splay})里,每一个( ext{splay})维护的东西都是一条在原树上从上到下按深度递增的一条链。
    然后我们定义每条边有两种类型:实或者虚。
    其中实边代表的是在某个( ext{splay})内部的边,而虚边则是某一个( ext{splay})所指向另一个节点所对应的边。
    然后这就是所谓的“实链剖分”了。而我们大家所熟知的树剖则是“重链剖分”。
    然后我们再来看一看各种操作。
    ( ext{access})操作
    这个操作代表的是打通一条根节点到现在节点的实链。
    我们可以选择的方法是从下往上拉。
    每次让要操作的节点成为当前( ext{splay})的根,然后将它的右子树变成( ext{0}),接着在根据虚边往上拉。
    你们可以画一棵树出来,更熟悉的理解一下。
    ( ext{access})操作是( ext{lct})的基础,其他操作全是在( ext{access})的基础上完成的。
    ( ext{makeroot})操作。
    这个操作就是换根操作。
    我们先要知道一点,那就是我们( ext{access})后这个节点一定是当前( ext{splay})中深度最大的节点。(应该容易理解,可以自行思考一下)。
    此时我们再让此节点成为当前( ext{splay})的根,那么这个节点一定是没有右子树的。
    这个时候我们有一个神奇的思路:
    直接把这个节点的左右子树交换,不就成了根了吗?
    事实证明这种思路是可行的。
    ( ext{findroot})操作
    ( ext{x})所在的树中的根。
    我们先( ext{access})一次,然后再( ext{splay})一次。
    此时的所有点都在当前节点的左子树里,毫无疑问,原来的树根就是目前为止一直左子树到最后一个的点。
    ( ext{split})操作
    这个操作的含义定义为拉出一条从( ext{x})( ext{y})的链。
    我们先( ext{makeroot(x)}),然后( ext{access(y)}),此时由于( ext{x})是根节点,所以( ext{x})( ext{y})就处在了同一个( ext{splay})中。
    这时我们再将( ext{y})变成现在( ext{splay})里的根就好了。
    ( ext{link})
    操作
    定义含义为连接某一条边。
    我们发现( ext{makeroot})之后由于是根节点,这个节点是没有父亲的,我们直接将这个节点的父亲赋为( ext{y})就好了。
    ( ext{cut})操作
    定义为删掉( ext{x})( ext{y})的边
    我们首先拉出一条从( ext{x})( ext{y})的链。
    一般来说( ext{cut})的时候一定是存在( ext{x})( ext{y})的边的,但是为了以防万一,这种特殊情况也要处理一下。
    有几种情况:
    1:( ext{y})不仅有( ext{x})一个儿子。
    2:( ext{x})的父亲不是( ext{y})
    3:( ext{x})有右孩子。
    然后你就可以写出( ext{lct})了。
    上代码:

    // luogu-judger-enable-o2
    #include <bits/stdc++.h>
    #define il inline
    const int maxn = 3e5 + 10; 
    using namespace std;
    template<class T> il void rd(T& res) {
        res = 0;char c;bool sign = 0;
        for(c = getchar();!isdigit(c);c = getchar()) sign |= c == '-';
        for(;isdigit(c);c = getchar()) res = (res << 1) + (res << 3) + (c ^ 48);    
        (sign) && (res = -res);
        return; 
    } 
    int n,m,i,j,k,root;     
    int ch[maxn][2],size[maxn],fa[maxn],val[maxn],sum[maxn];         
    bool tag[maxn],dbg;       
    il bool isroot(int o) {
        return ch[fa[o]][0] != o && ch[fa[o]][1] != o;
    }  
    il void push_up(int o) {
        size[o] = size[ch[o][0]] + size[ch[o][1]] + 1;
        sum[o] = sum[ch[o][0]] ^ sum[ch[o][1]] ^ val[o];
        return;
    }
    il void _swap(int& x,int& y) {
        x ^= y ^= x ^= y;
        return; 
    }
    il void push_down(int o) {
        if(tag[o]) {
            _swap(ch[o][0],ch[o][1]); 
            tag[ch[o][0]] ^= 1;
            tag[ch[o][1]] ^= 1;
            tag[o] = 0;
        }
        return;
    }
    il int which(int o) {
        return ch[fa[o]][1] == o;
    }
    il void rotate(int o) {
        int f = fa[o],gf = fa[f],whi = which(o);    
        if(!isroot(f)) ch[gf][which(f)] = o;      
        ch[f][whi] = ch[o][whi ^ 1];
        fa[ch[o][whi ^ 1]] = f;         
        ch[o][whi ^ 1] = f;        
        fa[f] = o;fa[o] = gf;       
     	push_up(f);push_up(o);
        return;	
    }            
    il void splay(int o) {
        stack<int> sta;
        while(!sta.empty()) sta.pop();sta.push(o);            
        for(int i = o;!isroot(i);i = fa[i]) sta.push(fa[i]);             
        while(!sta.empty()) push_down(sta.top()),sta.pop();
        for(int f = fa[o];!isroot(o);rotate(o),f = fa[o]) {   
            if(!isroot(f)) rotate(which(f) == which(o) ? f : o);     
        //	if(!dbg) printf("%d
    ",o); 
        }    
        push_up(o);
        return;
    }                                 
    il void access(int o) {        
        for(int y = 0;o;o = fa[y = o]) {           
            splay(o);      
            ch[o][1] = y;          
            push_up(o);
        }
    }    
    il int get_root(int o) {    
        access(o);splay(o);
        while(ch[o][0]) push_down(o),o = ch[o][0];    
        return o;
    }
    il void make_root(int o) {
        access(o);
        splay(o);          
        tag[o] ^= 1;
        return; 	
    } 
    il void link(int x,int y) {
        make_root(x);    
        fa[x] = y;
    }
    il void split(int x,int y) {
        make_root(x);
        access(y);
        splay(y);        
    }
    il void cut(int x,int y) {
        split(x,y);
        if(ch[y][which(x) ^ 1] || fa[x] != y || ch[x][1]) return;
        fa[x] = ch[y][0] = 0;
        push_up(y);
        return;
    }
    int main() {
        rd(n);rd(m);   
        for(int i = 1;i <= n;i++) rd(val[i]),sum[i] = val[i];
        for(int i = 1,op,x,y;i <= m;i++) {
            rd(op);rd(x);rd(y);     
            switch(op) {
                case 0: {
                    split(x,y);   
                    printf("%d
    ",sum[y]);
                    break;
                }
                case 1: {            
                    if(get_root(x) != get_root(y)) link(x,y);
                    break;
                }
                case 2: {
                    if(get_root(x) == get_root(y)) cut(x,y);
                    break;
                }
                case 3: {
                    val[x] = y;
                    access(x);
                    splay(x);
                    push_up(x);
                    break;
                }
            }
        }
        return 0;
    }
    
    
    
    
    
  • 相关阅读:
    CSS快速入门
    Kafka (一) 核心概念
    软件工程模型
    函数式编程
    spark计算操作整理
    HBase 文件合并
    HBase 数据存储结构
    目的论浅谈
    PHP8的注解
    JS的移入移除
  • 原文地址:https://www.cnblogs.com/Sai0511/p/11170873.html
Copyright © 2020-2023  润新知