题意
给一颗 n 个点的树,每一个点有一个颜色,然后维护几个操作。
操作 1:t=1 时,将 x 点的颜色修改为 y
操作 2:t=2 时,询问 x 到 y 路径上有多少个不同的颜色段
操作 3:t=3 时,询问 x 到 y 路径上的出现次数最多的颜色的出现次数
操作2是[SDOI2011]染色原题
操作3是树上带修莫队,关于如何求出出现次数最多的颜色出现次数,考虑到时莫队做法,一次只能+1或-1,所以ans也一定是+1或-1,可以用数组记下每种出现次数的总次数和,这样就可以在移动指针的时候修改ans了。
千万不要用树套树,考试时打了个线段树套动态开点线段树,空间完全开不下,只能过20分。。。
#include <bits/stdc++.h>
#define jh(x, y) (x ^= y, y ^= x, x ^= y)
#define ls (p << 1)
#define rs (p << 1 | 1)
#define li T2[p].l
#define ri T2[p].r
#define mid ((l + r) >> 1)
#define ll long long
using namespace std;
inline void read(int &x) {
x = 0; int f = 1; char ch = getchar();
while (!(ch >= '0' && ch <= '9')) { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + ch - 48; ch = getchar(); }
x *= f;
}
inline void Max(int &x, int y) { if (y > x) x = y; }
inline void Min(int &x, int y) { if (y < x) x = y; }
const int N = 1e5 + 10;
struct Seg1 { int lc, rc, sum; } T1[N << 2];
struct Edge { int b, nt; } e[N << 1];
struct Query { int opt, x, y; } query[N];
int head[N], e_num;
inline void anode(int u, int v) {
e[++e_num].b = v; e[e_num].nt = head[u]; head[u] = e_num;
}
///MO--------------------------------------------------------
int blo, cnta, cntc, tot, cur, pl = 1, pr = 0;
int ord[N << 1], ans[N], fir[N], sec[N], jp[N][21], cnt[N], out[N], res;
bool use[N];
#define bel(x) ((x - 1) / blo + 1)
struct Ask {
int l, r, lca, tim, aim;
bool operator < (const Ask &b) const {
if (bel(l) != bel(b.l)) return l < b.l;
if (bel(r) != bel(b.r)) return r < b.r;
return tim < b.tim;
}
} ask[N];
struct Chg { int aim, tim, val; } chg[N];
//mo----------------------------------------------------------
int n, Q, rt[N << 2];
queue<int> que;
int val[N];
int sz[N], prt[N], dep[N], son[N], bel[N], id, pos[N], h[N];
inline void dfs1(int u) {
fir[u] = ++tot;
ord[tot] = u;
sz[u] = 1;
for (int i = 1; i <= 20; i++) {
if ((1 << i) > dep[u]) break;
jp[u][i] = jp[jp[u][i - 1]][i - 1];
}
for (int i = head[u]; i; i = e[i].nt) {
int v = e[i].b;
if (v == prt[u]) continue;
prt[v] = u; dep[v] = dep[u] + 1; jp[v][0] = u;
dfs1(v);
sz[u] += sz[v];
if (sz[v] > sz[son[u]]) son[u] = v;
}
sec[u] = ++tot;
ord[tot] = u;
}
inline void dfs2(int u, int chain) {
bel[u] = chain;
pos[u] = ++id;
h[id] = u;
if (son[u]) dfs2(son[u], chain);
for (int i = head[u]; i; i = e[i].nt) {
int v = e[i].b;
if (v == prt[u] || v == son[u]) continue;
dfs2(v, v);
}
}
//SEG-----------------------------------------------------------
inline void pushup(int p) {
T1[p].sum = T1[ls].sum + T1[rs].sum;
if (T1[ls].rc == T1[rs].lc) --T1[p].sum;
T1[p].lc = T1[ls].lc, T1[p].rc = T1[rs].rc;
}
inline void build(int p, int l, int r) {
if (l == r) { T1[p].lc = T1[p].rc = val[h[l]]; T1[p].sum = 1; return; }
build(ls, l, mid), build(rs, mid + 1, r);
pushup(p);
}
inline void update(int p, int x, int v, int l = 1, int r = n) {
if (l == r) { T1[p].lc = T1[p].rc = v; T1[p].sum = 1; return; }
if (x <= mid) update(ls, x, v, l, mid);
else update(rs, x, v, mid + 1, r);
pushup(p);
}
inline int query_seg(int p, int L, int R, int l = 1, int r = n) {
if (l == L && r == R) return T1[p].sum;
if (R <= mid) return query_seg(ls, L, R, l, mid);
else if (L > mid) return query_seg(rs, L, R, mid + 1, r);
else {
int ret = query_seg(ls, L, mid, l, mid) + query_seg(rs, mid + 1, R, mid + 1, r);
if (T1[ls].rc == T1[rs].lc) --ret;
return ret;
}
}
inline int leaf_seg(int p, int x, int l = 1, int r = n) {
if (l == r) return T1[p].lc;
if (x <= mid) return leaf_seg(ls, x, l, mid);
else return leaf_seg(rs, x, mid + 1, r);
}
inline int query_chain(int x, int y) {
int ret = 0, down, up;
while (bel[x] != bel[y]) {
if (dep[bel[x]] < dep[bel[y]]) jh(x, y);
ret += query_seg(1, pos[bel[x]], pos[x]);
down = leaf_seg(1, pos[bel[x]]);
up = leaf_seg(1, pos[prt[bel[x]]]);
if (down == up) --ret;
x = prt[bel[x]];
}
if (dep[x] < dep[y]) jh(x, y);
ret += query_seg(1, pos[y], pos[x]);
return ret;
}
//query1-----------------------------------------------------
//MODUI------------------------------------------------------
inline int LCA(int x, int y) {
if (dep[x] < dep[y]) jh(x, y);
int t = dep[x] - dep[y];
for (int i = 0; i <= 20 && t; i++, t >>= 1)
if (t & 1) x = jp[x][i];
if (x == y) return x;
for (int i = 20; i >= 0; i--) if (jp[x][i] != jp[y][i])
x = jp[x][i], y = jp[y][i];
return prt[x];
}
inline void add(int x) {
if (cnt[val[x]]) --out[cnt[val[x]]];
++cnt[val[x]]; ++out[cnt[val[x]]];
Max(res, cnt[val[x]]);
}
inline void del(int x) {
if (cnt[val[x]]) --out[cnt[val[x]]];
--cnt[val[x]]; ++out[cnt[val[x]]];
if (!out[res]) --res;
}
inline void change(int x) {
int aim = chg[x].aim;
if (use[aim]) del(aim);
jh(val[aim], chg[x].val);
if (use[aim]) add(aim);
}
inline void gotime(int x) {
while (cur < cntc && chg[cur + 1].tim <= x) change(++cur);
while (cur && chg[cur].tim > x) change(cur--);
}
inline void work(int x) {
use[x] ^= 1;
if (use[x]) add(x); else del(x);
}
//ENDMO------------------------------------------------------
int main() {
freopen("cw.in", "r", stdin);
freopen("cw.out", "w", stdout);
read(n), read(Q);
for (int i = 1; i <= n; i++) read(val[i]);
for (int i = 1; i < n; i++) {
int u, v; read(u), read(v);
anode(u, v); anode(v, u);
}
dfs1(1); dfs2(1, 1);
build(1, 1, n);
for (int i = 1; i <= Q; i++) {
int opt, x, y; read(opt), read(x), read(y);
query[i].opt = opt, query[i].x = x, query[i].y = y;
if (opt == 1) chg[++cntc].aim = x, chg[cntc].val = y, chg[cntc].tim = i;
if (opt == 3) {
if (dep[x] < dep[y]) jh(x, y);
int lca = LCA(x, y);
++cnta, ask[cnta].aim = i, ask[cnta].tim = i;
if (lca == y) ask[cnta].l = fir[y], ask[cnta].r = fir[x], ask[cnta].lca = 0;
else ask[cnta].l = sec[y], ask[cnta].r = fir[x], ask[cnta].lca = lca;
}
}
blo = pow(tot, 0.666666);
sort(ask + 1, ask + 1 + cnta);
for (int i = 1; i <= cnta; i++) {
gotime(ask[i].tim);
while (pl < ask[i].l) work(ord[pl++]);
while (pl > ask[i].l) work(ord[--pl]);
while (pr < ask[i].r) work(ord[++pr]);
while (pr > ask[i].r) work(ord[pr--]);
ans[ask[i].aim] = res;
if (ask[i].lca && cnt[val[ask[i].lca]] == res) ++ans[ask[i].aim];
}
for (int i = 1; i <= Q; i++) {
if (query[i].opt == 1) update(1, bel[query[i].x], query[i].y);
else if (query[i].opt == 2) printf("%d\n", query_chain(query[i].x, query[i].y));
else printf("%d\n", ans[i]);
}
return 0;
}