「Template」Link Cut Tree

P3690

#include <cstdio>
#include <algorithm>

using namespace std;

#define LL long long
#define rep(i, j, k) for(int i = (j); i <= (k); i ++)
#define per(i, j, k) for(int i = (j); i >= (k); i --)

const int Maxn = 1e5;

struct Link_Cut_Tree {    
    struct Node {
        int rev;
        int sum, val;
        int fa, ch[2];
    } spl[Maxn + 5];

    #define fa(x) spl[x].fa
    #define sum(x) spl[x].sum
    #define val(x) spl[x].val
    #define rev(x) spl[x].rev
    #define son(x, d) spl[x].ch[d]

    void Pushup (int p) {
        sum (p) = sum (son (p, 0)) ^ (sum (son (p, 1))) ^ val (p);
    }
    void Flip (int p) { //第一种写法。。
        rev (p) ^= 1;
        swap (son (p, 0), son (p, 1));
    }
    void Pushdown (int p) {
        if (rev (p)) {
            rev (p) = 0;
            if (son (p, 0)) Flip (son (p, 0));
            if (son (p, 1)) Flip (son (p, 1));
        }
    }
    bool Isroot (int p) {
        return !fa (p) || (son (fa (p), 0) ^ p) && (son (fa (p), 1) ^ p);
    }
    bool Dir (int p) {
        return son (fa (p), 1) == p;
    }
    void Connect (int fa, int x, int d) {
        son (fa, d) = x, fa (x) = fa;
    }
    void Rotate (int x) {
        int y = fa (x), z = fa (y);
        int k1 = Dir (x), k2 = Dir (y);
        if (!Isroot (y)) son (z, k2) = x;
        fa (x) = z;
        Connect (y, son (x, k1 ^ 1), k1);
        Connect (x, y, k1 ^ 1);
        Pushup (y), Pushup (x);
    }
    void Push (int x) {
        if (!Isroot (x)) Push (fa (x));
        Pushdown (x);
    }
    void Splay (int p) {
        Push (p);
        while (!Isroot (p)) {
            int fa = spl[p].fa;
            if (!Isroot (fa)) {
                (Dir (fa) ^ Dir (p)) ? Rotate (p) : Rotate (fa);
            }
            Rotate (p);
        }
        Pushup (p);
    }
    void Access (int x) {
        for (int y = x, x = 0; y != 0; x = y, y = spl[y].fa) {
            Splay (y);
            son (y, 1) = x;
            Pushup (y);
        }
    } 
    int Find_Root (int p) {
        Access (p), Splay (p), Pushdown (p);
        while (son (p, 0)) p = son (p, 0), Pushdown (p);
        Splay (p);
        return p;
    }
    void Make_Root (int p) {
        Access (p), Splay (p), Flip (p);
    }
    void Link (int x, int y) {
        Make_Root (x);
        if (Find_Root (y) != x) fa (x) = y;
    }
    void Cut (int x, int y) {
        Make_Root (x);
        if (Find_Root (y) != x || son (y, 0) || fa (y) != x) return;
        fa (y) = 0, son (x, 1) = 0;
        Pushup (x);
    }
} lct;

int n, m;

int main () {
    scanf ("%d %d", &n, &m);

    rep (i, 1, n) {
        scanf ("%d", &lct.spl[i].val);
        lct.spl[i].sum = lct.spl[i].val;
    }

    rep (i, 1, m) {
        int op, x, y;
        scanf ("%d %d %d", &op, &x, &y);
        switch (op) {
            case 0 : {
                lct.Make_Root (x);
                lct.Access (y);
                lct.Splay (y);
                printf ("%d\n", lct.spl[y].sum);
                break;
            }
            case 1 : { lct.Link (x, y); break; }
            case 2 : { lct.Cut (x, y); break; }
            case 3 : {
                lct.Splay (x);
                lct.spl[x].val = y;
                break;
            }
        }
    }
    return 0;
}
#include <cstdio>
#include <algorithm>

using namespace std;

#define LL long long
#define rep(i, j, k) for(int i = (j); i <= (k); i ++)
#define per(i, j, k) for(int i = (j); i >= (k); i --)

const int Maxn = 1e5;

struct Link_Cut_Tree {    
    struct Node {
        int rev;
        int sum, val;
        int fa, ch[2];
    } spl[Maxn + 5];

    #define fa(x) spl[x].fa
    #define sum(x) spl[x].sum
    #define val(x) spl[x].val
    #define rev(x) spl[x].rev
    #define son(x, d) spl[x].ch[d]

    void Pushdown (int p) {
        if (rev (p)) {
            rev (p) = 0;
            swap (son (p, 0), son (p, 1));
            rev (son (p, 0)) ^= 1;
            rev (son (p, 1)) ^= 1;
        }
    }
    void Pushup (int p) {
        Pushdown (son (p, 0));
        Pushdown (son (p, 1));
//此题可以不写上面两句,但如果 pushup 时,与左右儿子的顺序有关就一定要写。
        sum (p) = sum (son (p, 0)) ^ (sum (son (p, 1))) ^ val (p);
    }
    bool Isroot (int p) {
        return !fa (p) || (son (fa (p), 0) ^ p) && (son (fa (p), 1) ^ p);
    }
    bool Dir (int p) {
        return son (fa (p), 1) == p;
    }
    void Connect (int fa, int x, int d) {
        son (fa, d) = x, fa (x) = fa;
    }
    void Rotate (int x) {
        int y = fa (x), z = fa (y);
        int k1 = Dir (x), k2 = Dir (y);
        if (!Isroot (y)) son (z, k2) = x;
        fa (x) = z;
        Connect (y, son (x, k1 ^ 1), k1);
        Connect (x, y, k1 ^ 1);
        Pushup (y), Pushup (x);
    }
    void Push (int x) {
        if (!Isroot (x)) Push (fa (x));
        Pushdown (x);
    }
    void Splay (int p) {
        Push (p);
        while (!Isroot (p)) {
            int fa = spl[p].fa;
            int gfa = spl[fa].fa;
            if (!Isroot (fa)) {
                (Dir (fa) ^ Dir (p)) ? Rotate (p) : Rotate (fa);
            }
            Rotate (p);
        }
        Pushup (p);
    }
    void Access (int x) {
        for (int y = x, x = 0; y != 0; x = y, y = spl[y].fa) {
            Splay (y);
            son (y, 1) = x;
            Pushup (y);
        }
    } 
    int Find_Root (int p) {
        Access (p), Splay (p), Pushdown (p);
        while (son (p, 0)) p = son (p, 0), Pushdown (p);
        Splay (p);
        return p;
    }
    void Make_Root (int p) {
        Access (p), Splay (p), rev (p) ^= 1;
    }
    void Link (int x, int y) {
        Make_Root (x);
        if (Find_Root (y) != x) fa (x) = y;
    }
    void Cut (int x, int y) {
        Make_Root (x);
        if (Find_Root (y) != x || son (y, 0) || fa (y) != x) return;
        fa (y) = 0, son (x, 1) = 0;
        Pushup (x);
    }

    #undef fa(x)
    #undef sum(x)
    #undef val(x)
    #undef rev(x)
    #undef son(x, d)
} lct;

int n, m;

int main () {
    scanf ("%d %d", &n, &m);

    rep (i, 1, n) {
        scanf ("%d", &lct.spl[i].val);
        lct.spl[i].sum = lct.spl[i].val;
    }

    rep (i, 1, m) {
        int op, x, y;
        scanf ("%d %d %d", &op, &x, &y);
        switch (op) {
            case 0 : {
                lct.Make_Root (x);
                lct.Access (y);
                lct.Splay (y);
                printf ("%d\n", lct.spl[y].sum);
                break;
            }
            case 1 : { lct.Link (x, y); break; }
            case 2 : { lct.Cut (x, y); break; }
            case 3 : {
                lct.Splay (x);
                lct.spl[x].val = y;
                // lct.Pushup (x);
                break;
            }
        }
    }
    return 0;
}
posted @ 2022-03-11 22:12  PoisonNNN  阅读(51)  评论(0编辑  收藏  举报