这道题真的变态。
先树剖。然后在线段树上维护1个标记
cor:对应区间右端点的颜色。
T:对应区间的颜色段数。
合并两个区间,就是将左子区间和右子区间的
同样,在路径询问中,将一条路径映射成若干个区间后,如果相邻的两个区间对应的路径,它们的相交处(也就是这两条子路径中相邻的一对点)颜色相同,那么累计答案时,要把答案减1。
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define p2 p << 1
#define p3 p << 1 | 1
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
inline char get() {
char c; while ((c = getchar()) != 'C' && c != 'Q');
return c;
}
const int N = 1e5 + 5;
int n, m, a[N], ecnt, nxt[N << 1], adj[N], go[N << 1], T[N << 2],
tag[N << 2], col[N << 2], cor[N << 2], fa[N], dep[N], sze[N], son[N],
top[N], pos[N], idx[N], tot;
struct ask_q {int len, col, cor;};
void add_edge(int u, int v) {
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;
}
void down(int p) {
if (tag[p] != -1) {
tag[p2] = tag[p]; tag[p3] = tag[p];
tag[p] = -1;
}
}
void calc(int p) {
col[p] = tag[p2] == -1 ? col[p2] : tag[p2];
cor[p] = tag[p3] == -1 ? cor[p3] : tag[p3];
int lp = tag[p2] == -1 ? T[p2] : 1,
rp = tag[p3] == -1 ? T[p3] : 1,
li = tag[p2] == -1 ? cor[p2] : tag[p2],
ri = tag[p3] == -1 ? col[p3] : tag[p3];
T[p] = lp + rp - (li == ri);
}
void build(int l, int r, int p) {
if (l == r) {
T[p] = 1; col[p] = cor[p] = a[idx[l]];
tag[p] = -1; return;
}
int mid = l + r >> 1;
build(l, mid, p2); build(mid + 1, r, p3);
tag[p] = -1; col[p] = col[p2]; cor[p] = cor[p3];
T[p] = T[p2] + T[p3] - (cor[p2] == col[p3]);
}
void change(int l, int r, int s, int e, int v, int p) {
if (l == s && r == e) return (void) (tag[p] = v);
int mid = l + r >> 1; down(p);
if (e <= mid) change(l, mid, s, e, v, p2);
else if (s >= mid + 1) change(mid + 1, r, s, e, v, p3);
else change(l, mid, s, mid, v, p2),
change(mid + 1, r, mid + 1, e, v, p3);
calc(p);
}
ask_q ask(int l, int r, int s, int e, int p) {
if (l == s && r == e) {
ask_q rw;
rw.len = tag[p] == -1 ? T[p] : 1;
rw.col = tag[p] == -1 ? col[p] : tag[p];
rw.cor = tag[p] == -1 ? cor[p] : tag[p];
return rw;
}
int mid = l + r >> 1; down(p); ask_q z, t, uv;
if (e <= mid) {
z = ask(l, mid, s, e, p2);
uv.len = z.len; uv.col = z.col; uv.cor = z.cor;
}
else if (s >= mid + 1) {
z = ask(mid + 1, r, s, e, p3);
uv.len = z.len; uv.col = z.col; uv.cor = z.cor;
}
else {
z = ask(l, mid, s, mid, p2); t = ask(mid + 1, r, mid + 1, e, p3);
uv.len = z.len + t.len - ((tag[p2] == -1 ? cor[p2] : tag[p2])
== (tag[p3] == -1 ? col[p3] : tag[p3]));
uv.col = z.col; uv.cor = t.cor;
}
calc(p); return uv;
}
void dfs1(int u, int fu) {
sze[u] = 1; dep[u] = dep[fu] + 1; fa[u] = fu;
for (int e = adj[u], v; e; e = nxt[e])
if ((v = go[e]) != fu) {
dfs1(v, u); sze[u] += sze[v];
if (sze[v] > sze[son[u]]) son[u] = v;
}
}
void dfs2(int u, int fu) {
if (son[u]) {
idx[pos[son[u]] = ++tot] = son[u];
top[son[u]] = top[u];
dfs2(son[u], u);
}
for (int e = adj[u], v; e; e = nxt[e])
if ((v = go[e]) != fa[u] && v != son[u])
idx[pos[v] = ++tot] = v, top[v] = v, dfs2(v, u);
}
void path_change(int u, int v, int w) {
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
change(1, n, pos[top[u]], pos[u], w, 1); u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v); change(1, n, pos[u], pos[v], w, 1);
}
int path_query(int u, int v) {
int res = 0, cu = -1, cv = -1; ask_q rr;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v), swap(cu, cv);
rr = ask(1, n, pos[top[u]], pos[u], 1); res += rr.len;
if (rr.cor == cu) res--; cu = rr.col;
u = fa[top[u]];
}
if (dep[u] > dep[v]) swap(u, v), swap(cu, cv);
rr = ask(1, n, pos[u], pos[v], 1);
return res + rr.len - (rr.col == cu) - (rr.cor == cv);
}
int main() {
int i, x, y, z; char c;
n = read(); m = read();
for (i = 1; i <= n; i++) a[i] = read();
for (i = 1; i < n; i++) {
x = read(); y = read();
add_edge(x, y); add_edge(y, x);
}
dfs1(1, 0); tot = top[1] = pos[1] = idx[1] = 1;
dfs2(1, 0); build(1, n, 1);
while (m--) {
c = get(); x = read(); y = read();
if (c == 'C') z = read(), path_change(x, y, z);
else printf("%d\n", path_query(x, y));
}
return 0;
}