题目大意:有一棵以$1$为根的有根树,有$n$个点,每个节点初始有颜色$c_i$。有两种操作:
$1 v c:$将以$v$为根的子树中所有点颜色更改为$c$
$2 v:$ 查询以$v$为根的子树中的节点有多少种不同的颜色
题解:只有$60$种颜色,可以考虑用一个$long;long$把颜色状压,用$dfs$序把树上问题转化为线段问题就行了
卡点:各种该开$long;long$开$int$
C++ Code:
#include <cstdio> #define maxn 400010 using namespace std; int head[maxn], cnt; struct Edge { int to, nxt; } e[maxn << 1]; void add(int a, int b) { e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt; } int n, m, a; long long w[maxn], W[maxn]; long long V[maxn << 2], cov[maxn << 2]; int dfn[maxn], dfn_o[maxn], idx; void dfs(int rt) { dfn[rt] = ++idx; for (int i = head[rt]; i; i = e[i].nxt) { int v = e[i].to; if (!dfn[v]) { dfs(v); } } dfn_o[rt] = idx; } void build(int rt, int l, int r) { cov[rt] = -1; if (l == r) { V[rt] = w[l]; return ; } int mid = l + r >> 1; build(rt << 1, l, mid); build(rt << 1 | 1, mid + 1, r); V[rt] = V[rt << 1] | V[rt << 1 | 1]; } void pushdown(int rt) { long long &tmp = cov[rt]; int lc = rt << 1, rc = rt << 1 | 1; cov[rc] = cov[lc] = V[rc] = V[lc] = tmp; tmp = -1; } void add(int rt, int l, int r, int L, int R, long long num) { if (L <= l && R >= r) { V[rt] = num; cov[rt] = num; return ; } if (~cov[rt]) pushdown(rt); int mid = l + r >> 1; if (L <= mid) add(rt << 1, l, mid, L, R, num); if (R > mid) add(rt << 1 | 1, mid + 1, r, L, R, num); V[rt] = V[rt << 1] | V[rt << 1 | 1]; } long long ask(int rt, int l, int r, int L, int R) { if (L <= l && R >= r) { return V[rt]; } if (~cov[rt]) pushdown(rt); int mid = l + r >> 1; long long ans = 0; if (L <= mid) ans = ask(rt << 1, l, mid, L, R); if (R > mid) ans = ans | ask(rt << 1 | 1, mid + 1, r, L, R); return ans; } int count(long long num) { int ans = 0; while (num) { ans += num & 1; num >>= 1; } return ans; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%d", &a); W[i] = 1ll << a - 1; } for (int i = 1; i < n; i++) { int a, b; scanf("%d%d", &a, &b); add(a, b); add(b, a); } dfs(1); for (int i = 1; i <= n; i++) w[dfn[i]] = W[i]; build(1, 1, n); while (m --> 0) { int op, x, y; scanf("%d%d", &op, &x); if (op --> 1) { long long tmp = ask(1, 1, n, dfn[x], dfn_o[x]); printf("%d ", count(tmp)); } else { scanf("%d ", &y); add(1, 1, n, dfn[x], dfn_o[x], 1ll << y - 1); } } return 0; }