[SDOI 2011] 染色

题目大意

一个 nn 个节点的树,每个节点有一个权值 cic_i,给出 mm 组操作,每次操作为:

  • C  a  b  cC \; a \; b \; c:把链 aba-b 上的节点的权值全部修改为 cc
  • Q  a  bQ \; a \; b:询问链 aba-b 上有几段权值。

1n,  m100,0001 \leqslant n, \; m \leqslant 100,000

0ci1,000,000,0000 \leqslant c_i \leqslant 1,000,000,000

题目链接

【SDOI 2011】染色 - Luogu 2486

题解

树链剖分裸题。

一直懒得做,今天做了之后被各种细节错误坑惨了(代码中所有有 DBG 的地方几乎都是出过错的地方)。。。

代码

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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
#include <cstdio>
#include <algorithm>
// #define DBG
const int MAXN = 100005;
struct Edge;
struct Chain;
struct Node {
Edge *e;
Chain *c;
Node *fa, *maxChild;
int size, dfn, deep;
bool vis;
#ifdef DBG
int id;
#endif
} N[MAXN];
struct Edge {
Node *u, *v;
Edge *next;
Edge(Node *u, Node *v) : u(u), v(v), next(u->e) {}
};
struct Chain {
Node *top;
Chain(Node *top) : top(top) {}
};
void addEdge(int u, int v) {
N[u].e = new Edge(&N[u], &N[v]);
N[v].e = new Edge(&N[v], &N[u]);
}
void dfs1(Node *u) {
u->vis = true;
u->size = 1;
#ifdef DBG
printf("dfs1(%d)\n", u->id);
#endif
for (Edge *e = u->e; e; e = e->next) {
#ifdef DBG
printf("when dfs1(%d), v: %d\n", u->id, e->v->id);
#endif
if (e->v->vis) continue;
e->v->fa = u;
e->v->deep = u->deep + 1;
dfs1(e->v);
u->size += e->v->size;
if (!u->maxChild || u->maxChild->size < e->v->size) u->maxChild = e->v;
}
#ifdef DBG
printf("end dfs1(%d)\n", u->id);
#endif
}
void dfs2(Node *u) {
static int dfsClock = 0;
u->dfn = ++dfsClock;
if (!u->fa || u != u->fa->maxChild) u->c = new Chain(u);
else u->c = u->fa->c;
if (u->maxChild) dfs2(u->maxChild);
for (Edge *e = u->e; e; e = e->next)
if (e->v->fa == u && e->v != u->maxChild) dfs2(e->v);
}
void split() {
N[1].deep = 1;
dfs1(&N[1]);
#ifdef DBG
puts("after dfs1");
#endif
dfs2(&N[1]);
}
struct SegT {
struct Node {
int l, r, mid;
Node *lc, *rc;
int cnt, val, lval, rval, tag;
Node(int l, int r, Node *lc, Node *rc) : l(l), r(r), lc(lc), rc(rc), cnt(0), val(0), lval(0), rval(0), tag(-1) {}
void maintain() {
cnt = lc->cnt + rc->cnt - (lc->rval == rc->lval);
lval = lc->lval;
rval = rc->rval;
}
void pushDown() {
if (tag != -1) {
val = lval = rval = tag;
cnt = 1;
if (lc) lc->tag = tag;
if (rc) rc->tag = tag;
tag = -1;
}
}
void update(int pos, int v) {
#ifdef DBG
printf("update(%d) in [%d, %d] to %d\n", pos, l, r, v);
#endif
pushDown();
if (l == r) {
val = lval = rval = v;
cnt = 1;
return;
}
int mid = l + (r - l) / 2;
if (pos <= mid) lc->update(pos, v);
else rc->update(pos, v);
maintain();
}
void update(int l, int r, int v) {
#ifdef DBG
printf("update[%d, %d] in [%d, %d] to %d\n", l, r, this->l, this->r, v);
#endif
pushDown();
if (r < this->l || this->r < l) return;
if (l <= this->l && this->r <= r) {
tag = v;
pushDown();
return;
}
lc->update(l, r, v);
rc->update(l, r, v);
maintain();
}
int query(int pos) {
#ifdef DBG
printf("queryVal in [%d, %d], val = %d\n", l, r, val);
#endif
pushDown();
if (l == r) return val;
int mid = l + (r - l) / 2;
if (pos <= mid) return lc->query(pos);
else return rc->query(pos);
}
int query(int l, int r) {
#ifdef DBG
printf("query[%d, %d] in [%d, %d], cnt = %d\n", l, r, this->l, this->r, cnt);
#endif
pushDown();
if (r < this->l || this->r < l) return 0;
if (l <= this->l && this->r <= r) return cnt;
int res = lc->query(l, r) + rc->query(l, r);
int mid = this->l + (this->r - this->l) / 2;
if (l <= mid && mid < r && lc->rval == rc->lval) res--;
return res;
}
} *root;
SegT() : root(NULL) {}
static Node *build(int l, int r) {
if (l == r) return new Node(l, r, NULL, NULL);
int mid = l + (r - l) / 2;
return new Node(l, r, build(l, mid), build(mid + 1, r));
}
void update(int pos, int v) {
root->update(pos, v);
}
void update(int l, int r, int v) {
root->update(l, r, v);
}
int query(int pos) {
return root->query(pos);
}
int query(int l, int r) {
return root->query(l, r);
}
} segT;
int n, m, c[MAXN];
void update(int a, int b, int val) {
Node *u = &N[a], *v = &N[b];
while (u->c != v->c) {
if (u->c->top->deep < v->c->top->deep) std::swap(u, v);
segT.update(u->c->top->dfn, u->dfn, val);
u = u->c->top->fa;
}
if (u->deep > v->deep) std::swap(u, v);
segT.update(u->dfn, v->dfn, val);
}
int query(int a, int b) {
Node *u = &N[a], *v = &N[b];
int res = 0;
while (u->c != v->c) {
if (u->c->top->deep < v->c->top->deep) std::swap(u, v);
res += segT.query(u->c->top->dfn, u->dfn);
#ifdef DBG
printf("query(%d, %d), res = %d(before -)\n", a, b, res);
#endif
if (segT.query(u->c->top->dfn) == segT.query(u->c->top->fa->dfn)) res--;
#ifdef DBG
printf("query(%d, %d), res = %d\n", a, b, res);
#endif
u = u->c->top->fa;
}
if (u->deep > v->deep) std::swap(u, v);
res += segT.query(u->dfn, v->dfn);
return res;
}
int main() {
scanf("%d %d", &n, &m);
#ifdef DBG
for (int i = 1; i <= n; i++) N[i].id = i;
#endif
for (int i = 1; i <= n; i++) scanf("%d", &c[i]);
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d %d", &u, &v);
addEdge(u, v);
}
split();
#ifdef DBG
puts("after split");
#endif
segT.root = SegT::build(1, n);
for (int i = 1; i <= n; i++) segT.update(N[i].dfn, c[i]);
#ifdef DBG
puts("after build");
#endif
while (m--) {
#ifdef DBG
printf("m = %d\n", m);
#endif
char op[2];
int a, b;
scanf("%s %d %d", op, &a, &b);
if (op[0] == 'C') {
int c;
scanf("%d", &c);
update(a, b, c);
} else printf("%d\n", query(a, b));
}
return 0;
}