洛谷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;
}
浙公网安备 33010602011771号