LCT板子啊啊啊啊

/*
LCT 基本操作
看起来也不是很长啊, 主要是要理解了来记住他
首先辅助的splay 是按照数组位置为权值维护的, 所以可以直接用下标判断即可
每个点的键值为这个点的深度,即这棵Splay的中序遍历是这条链从链顶到链底的所有节点构成的序列
虚边就是父亲没有指向那个儿子, 但是 儿子指向了父亲
实边就是父亲指向了儿子
没边就是互相没指
access操作
将一个点的重儿子切断, 并且使这个点到根节点的所有边变成实边
方法: 将这个点splay到该splay的根, 然后将他的右二子改成上一块的根
原因是他的右二子要么是不连接节点的, 要么是原来的重儿子, 这样就能起到改重儿子的效果了

make_root操作
将一个节点弄到根上
首先打通x, 发现根到x是一条链, x是链尾, 将他splay到根后, 他是链头, 由于我们是按照深度维护 的, 所以区间翻转一下

find_root操作 
查询原树根
makeroot后, 原树根本来应该在最右儿子, 奈何翻转了, 于是查询最左儿子即可

link 操作
树上加边, 将x弄成根, 父亲改成y即可

split操作
分离出x - y的splay 就可以查询整棵splay的信息了
首先将xmakeroot, 然后access(y) 这样提取出了x - y的splay, 为了方便我们直接提取树根的信息, 我们再把ysplay到根即可

cut操作
首先split x y
然后如果边x, y存在的话 , x 应该在y的左儿子并且x应当没有又儿子 

然而我现在才学lct是不是凉凉了啊
*/
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#include<cmath>
#define ll long long
#define M 300010
#define mmp make_pair
using namespace std;
int read() {
    int nm = 0, f = 1;
    char c = getchar();
    for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0';
    return nm * f;
}

struct L {
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
#define isr(x) (ch[fa[x]][0] != x && ch[fa[x]][1] != x)
    int ch[M][2], fa[M], rev[M], sum[M], ver[M];
    int wh(int x) {
        return ch[fa[x]][1] == x;
    }
    void pushup(int x) {
        sum[x] = sum[ls(x)] ^ sum[rs(x)] ^ ver[x];
    }
    void add(int x) {
        rev[x] ^= 1;
        swap(ls(x), rs(x));
    }
    void pushdown(int x) {
        if(rev[x]) {
            add(ls(x));
            add(rs(x));
            rev[x] = 0;
        }
    }
    void pd(int x) {
        if(!isr(x)) pd(fa[x]);
        pushdown(x);
    }
    void rotate(int x) {
        int y = fa[x], q = fa[y];
        bool dy = wh(x), dz = wh(y);
        if(!isr(y)) ch[q][dz] = x;
        fa[x] = q;
        fa[ch[x][dy ^ 1]] = y;
        ch[y][dy] = ch[x][dy ^ 1];
        ch[x][dy ^ 1] = y;
        fa[y] = x;
        pushup(y);
        pushup(x);
    }
    void splay(int x) {
        pd(x);
        while(!isr(x)) {
            int y = fa[x], q = fa[y];
            if(!isr(y)) {
                if((ch[y][1] == x) ^ (ch[q][1] == y)) rotate(x);
                else rotate(y);
            }
            rotate(x);
        }
    }
    void access(int x) {
        for(int y = 0; x; y = x, x = fa[x]) splay(x), rs(x) = y, pushup(x);
    }
    void maker(int x) {
        access(x);
        splay(x);
        add(x);
    }
    int findr(int x) {
        access(x);
        splay(x);
        while(ls(x)) pushdown(x), x = ls(x);
        return x;
    }
    void link(int x, int y) {
        maker(x), fa[x] = y;
    }

    void cut(int x, int y) {
        maker(x), access(y), splay(y);
        if(fa[x] != y || ch[x][1]) return;
        fa[x] = ch[y][0] = 0;
        pushup(y);
    }
    void split(int x, int y) {
        maker(x), access(y), splay(y);
    }
} lct;

int n, q;

int main() {
    n = read(), q = read();
    for(int i = 1; i <= n; i++) lct.ver[i] = read();
    while(q--) {
        int a = read(), b = read(), c = read();
        if(a == 0) lct.split(b, c), cout << lct.sum[c] << "\n";
        if(a == 1) if(lct.findr(b) != lct.findr(c)) lct.link(b, c);
        if(a == 2) if(lct.findr(b) == lct.findr(c)) lct.cut(b, c);
        if(a == 3) lct.ver[b] = c, lct.splay(b);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/luoyibujue/p/10073215.html