挺好的一道题
Description
给一棵树,每个点有颜色 (c_i) 为点权,需要实现以下两种操作:
子树修改颜色(覆盖),查询子树颜色种类
(n leq 4 imes 10^5,c_i leq 60)
Solution
首先看到子树和修改啥的,直接思考 (dfs) 序加线段树(从树剖学来的)
我们看到如果对于每一个点开桶进行统计,可能不太现实
然后审题的关键点就来了:(c_i leq 60)
可以开 ( m{long long}) 状压
然后就成了单点进行答案统计
最后把对应 (query) 搞个 (lowbit) 什么的整一下 (1) 就好了(从树状数组剽来的)
要注意 (1ll<<)的问题
Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm {
inline int read() {
int res = 0, f = 1;
char k;
while (!isdigit(k = getchar()))
if (k == '-')
f = -1;
while (isdigit(k)) res = res * 10 + k - '0', k = getchar();
return res * f;
}
const int N = 4e5 + 10;
int a[N], fa[N], dep[N], head[N], cnt, in[N], out[N], tim, opt, n, m, id[N];
struct node {
int nxt, to;
} e[N << 2];
inline void add1(int u, int v) {
e[++cnt].nxt = head[u];
e[cnt].to = v;
return head[u] = cnt, void();
}
struct tree {
int l, r, sum, add;
#define l(p) t[p].l
#define r(p) t[p].r
#define sum(p) t[p].sum
#define add(p) t[p].add
} t[N << 2];
inline void push_up(int p) {
sum(p) = sum(p << 1) | sum(p << 1 | 1);
return;
}
inline void build(int p, int l, int r) {
l(p) = l;
r(p) = r;
if (l == r)
return sum(p) = 1ll << a[id[l]], void();
int mid = (l + r) >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
return push_up(p);
}
inline int lowbit(int x) { return x & (-x); }
inline void spread(int p) {
if (add(p)) {
sum(p << 1) = add(p);
sum(p << 1 | 1) = add(p);
add(p << 1) = add(p);
add(p << 1 | 1) = add(p);
}
return add(p) = 0, void();
}
inline void update(int p, int l, int r, int c) {
if (l <= l(p) && r(p) <= r)
return add(p) = 1ll << c, sum(p) = 1ll << c, void();
spread(p);
int mid = (l(p) + r(p)) >> 1;
if (l <= mid)
update(p << 1, l, r, c);
if (r > mid)
update(p << 1 | 1, l, r, c);
return push_up(p);
}
inline int query(int p, int l, int r) {
if (l <= l(p) && r(p) <= r)
return sum(p);
spread(p);
int ans = 0, mid = (l(p) + r(p)) >> 1;
if (l <= mid)
ans |= query(p << 1, l, r);
if (r > mid)
ans |= query(p << 1 | 1, l, r);
return ans;
}
inline int ask1(int x) {
int ret = 0;
for (; x; x -= lowbit(x)) ret++;
return ret;
}
inline void dfs(int x, int f) {
in[x] = ++tim;
id[tim] = x;
fa[x] = f;
for (int i = head[x]; i; i = e[i].nxt) {
int t = e[i].to;
if (t == f)
continue;
dfs(t, x);
}
return out[x] = tim, void();
}
signed main() {
n = read(), m = read();
for (int i = 1; i <= n; ++i) a[i] = read();
for (int i = 1, u, v; i < n; ++i) u = read(), v = read(), add1(u, v), add1(v, u);
dfs(1, 0);
build(1, 1, n);
while (m--) {
opt = read();
if (opt == 1) {
int x = read(), c = read();
update(1, in[x], out[x], c);
} else {
int x = read();
int tmp = query(1, in[x], out[x]);
printf("%lld
", ask1(tmp));
}
}
return 0;
}
} // namespace yspm
signed main() { return yspm::main(); }