a481. 樹的維護

contents

  1. 1. Problem
  2. 2. Sample Input
  3. 3. Sample Output
  4. 4. Solution

Problem

操作有三種

  • 1 x y 詢問樹路徑 x - y 經過的點權重和
  • 2 x w 修改 x 的點權為 w
  • 3 x yx 父節點修改成 y

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
5
0 1
1 2
1 3
2 4
2 5
5
1 3 5
2 1 2
1 3 5
3 2 3
1 3 5

Sample Output

1
2
3
11
12
10

Solution

題目看起來是一個有根樹,由於權重落在點上,又由於父節點修改可以用額外數組紀錄,因此可以當作無向樹操作。

假設知道一條邊的兩端點 e(u, v),進行 cut(u, v) 操作,不知道誰父誰子的切割時,可以轉兩次通到樹根,讓另一端點落在左子樹。

1
2
3
4
5
void cut(Node *x, Node *y) {
mk_root(x);
access(y), splay(y);
y->ch[0] = x->fa = Node::EMPTY;
}

由於是無向樹,詢問路徑則藉由將其中一端變成根,接著藉由 access() 將路徑接到樹根,再藉由 splay() 轉到 splay tree 的根,此時帶權值就是路徑總和。

1
2
3
4
5
int sumPath(Node *x, Node *y) {
mk_root(x);
access(y), splay(y);
return y->sum;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <bits/stdc++.h>
using namespace std;
class LCT { // Link-Cut Tree
public:
static const int MAXN = 131072;
struct Node {
static Node *EMPTY;
Node *ch[2], *fa;
int rev;
int val, sum, size;
Node() {
ch[0] = ch[1] = fa = NULL;
rev = 0;
val = sum = size = 1;
}
bool is_root() {
return fa->ch[0] != this && fa->ch[1] != this;
}
void pushdown() {
if (rev) {
ch[0]->rev ^= 1, ch[1]->rev ^= 1;
swap(ch[0], ch[1]);
rev ^= 1;
}
}
void pushup() {
sum = val, size = 1;
if (ch[0] != EMPTY)
sum += ch[0]->sum, size += ch[0]->size;
if (ch[1] != EMPTY)
sum += ch[1]->sum, size += ch[1]->size;
}
inline void push_deal(int c) {
val = c;
pushup();
}
} _mem[MAXN];
int bufIdx;
LCT() {
Node::EMPTY = &_mem[0];
Node::EMPTY->fa = Node::EMPTY->ch[0] = Node::EMPTY->ch[1] = Node::EMPTY;
bufIdx = 1;
}
void init() {
bufIdx = 1;
}
Node* newNode() {
Node *u = &_mem[bufIdx++];
*u = Node();
u->fa = u->ch[0] = u->ch[1] = Node::EMPTY;
return u;
}
void rotate(Node *x) {
Node *y;
int d;
y = x->fa, d = y->ch[1] == x ? 1 : 0;
x->ch[d^1]->fa = y, y->ch[d] = x->ch[d^1];
x->ch[d^1] = y;
if (!y->is_root())
y->fa->ch[y->fa->ch[1] == y] = x;
x->fa = y->fa, y->fa = x;
y->pushup(), x->pushup();
}
void deal(Node *x) {
if (!x->is_root()) deal(x->fa);
x->pushdown();
}
void splay(Node *x) {
Node *y, *z;
deal(x);
while (!x->is_root()) {
y = x->fa, z = y->fa;
if (!y->is_root()) {
if (y->ch[0] == x ^ z->ch[0] == y)
rotate(x);
else
rotate(y);
}
rotate(x);
}
x->pushup();
}
void access(Node *u) {
Node *v = Node::EMPTY;
for (; u != Node::EMPTY; u = u->fa) {
splay(u);
u->ch[1] = v;
v = u;
v->pushup();
}
}
void mk_root(Node *u) {
access(u), splay(u);
u->rev ^= 1;
}
void cut(Node *x, Node *y) {
mk_root(x);
access(y), splay(y);
y->ch[0] = x->fa = Node::EMPTY;
}
void link(Node *x, Node *y) {
mk_root(x);
x->fa = y;
}
Node* find(Node *x) {
access(x), splay(x);
for (; x->ch[0] != Node::EMPTY; x = x->ch[0]);
return x;
}
//
void dealNode(Node *x, int c) {
mk_root(x);
x->push_deal(c);
}
int sumPath(Node *x, Node *y) {
mk_root(x);
access(y), splay(y);
return y->sum;
}
} tree;
LCT::Node *LCT::Node::EMPTY;
LCT::Node *A[131072], *node_x, *node_y;
int p[131072];
int main() {
int n, m, x, y, c, u, v, cmd;
while (scanf("%d", &n) == 1) {
tree.init();
for (int i = 1; i <= n; i++)
A[i] = tree.newNode();
for (int i = 1; i <= n; i++) {
scanf("%d %d", &p[i], &y);
if (p[i])
tree.link(A[i], A[p[i]]);
tree.dealNode(A[i], y);
}
scanf("%d", &m);
for (int i = 0; i < m; i++) {
scanf("%d %d %d", &cmd, &x, &y);
if (cmd == 1) {
printf("%d\n", tree.sumPath(A[x], A[y]));
} else if (cmd == 2) {
tree.dealNode(A[x], y);
} else if (cmd == 3) {
tree.cut(A[x], A[p[x]]);
tree.link(A[x], A[y]);
p[x] = y;
}
}
}
return 0;
}