洛谷P3690 【模板】动态树(LCT) 题解 LCT模板题

题目链接:https://www.luogu.com.cn/problem/P3690

解题思路来自 《算法竞赛》这本书 (注:书中代码有些许bug,这里没有~)

代码参考自 算法竞赛书本中的代码,即 ecnerwaIa大佬的博客

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;

struct Node {
    int s[2], p, v, sum, lazy;

    Node() {};
    Node(int _v, int _p) { s[0] = s[1] = lazy = 0; sum = v = _v; p = _p; }
} tr[maxn];
#define ls(u) tr[u].s[0]
#define rs(u) tr[u].s[1]

bool is_root(int x) {
    int p = tr[x].p;
    return ls(p) != x && rs(p) != x;
}

void push_up(int x) {
    tr[x].sum = tr[x].v ^ tr[ls(x)].sum ^ tr[rs(x)].sum;
}

void reverse(int x) {
    if (!x) return;
    swap(ls(x), rs(x));
    tr[x].lazy ^= 1;
}

void push_down(int x) {
    if (tr[x].lazy) {
        reverse(ls(x));
        reverse(rs(x));
        tr[x].lazy = 0;
    }
}

void push(int x) {
    if (!is_root(x)) push(tr[x].p); // 从根到x全部翻转
    push_down(x);
}

void f_s(int p, int u, bool k) {
    if (p) tr[p].s[k] = u;
    if (u) tr[u].p = p;
}

void rot(int x) {
    int y = tr[x].p, z = tr[y].p;
    bool k = tr[y].s[1] == x;
    if (!is_root(y))
        tr[z].s[ tr[z].s[1] == y ] = x;
    tr[x].p = z;
    tr[y].s[k] = tr[x].s[k^1];
    f_s(y, tr[x].s[k^1], k);
    f_s(x, y, k^1);
    push_up(y), push_up(x);
}

void splay(int x) { // 提根:把x旋转为它所在的splay树的根
    push(x);
    while (!is_root(x)) {
        int y = tr[x].p, z = tr[y].p;
        if (!is_root(y))
            (tr[y].s[1]==x) ^ (tr[z].s[1]==y) ? rot(x) : rot(y);
        rot(x);
    }
}

void access(int x) {    // 在原树上建一条实链,起点是根,终点是x
    for (int son = 0; x; son = x, x = tr[x].p) {
        splay(x);
        rs(x) = son;
        push_up(x);
    }
}

void make_root(int x) {     // 把 x 在原树上旋转到根的位置
    access(x); splay(x); reverse(x);
}

void split(int x, int y) {  // 把原树上以x为起点,以y为终点的路径,生成一条实链
    make_root(x);
    access(y);
    splay(y);
}

void link(int x, int y) {   // 在节点x和y之间连接一条边
    make_root(x); tr[x].p = y;
}

void cut(int x, int y) {    // 将连接x和y的边断开
    split(x, y);
    if (ls(y) != x || rs(x)) return;
    tr[x].p = ls(y) = 0;
    push_up(y);
}

int find_root(int x) {
    access(x); splay(x);
    while (ls(x)) push_down(x), x = ls(x);
    splay(x);
    return x;
}

int n, m;

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1, v; i <= n; i++) {
        scanf("%d", &v);
        tr[i] = Node(v, 0);
    }
    for (int i = 0, op, x, y; i < m; i++) {
        scanf("%d%d%d", &op, &x, &y);
        if (op == 0) {
            split(x, y);
            printf("%d\n", tr[y].sum);
        }
        else if (op == 1) {
            if (find_root(x) != find_root(y))
                link(x, y);
        }
        else if (op == 2) {
            cut(x, y);
        }
        else { // op == 3
            splay(x);
            tr[x].v = y;
            push_up(x);
        }
    }
    return 0;
}
posted @ 2026-06-05 11:35  quanjun  阅读(7)  评论(0)    收藏  举报