[CF620E]New Year Tree

题目大意:有一棵以$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\n", count(tmp));
		} else {
			scanf("%d\n", &y);
			add(1, 1, n, dfn[x], dfn_o[x], 1ll << y - 1);
		}
	}
	return 0;
}

  

posted @ 2018-08-15 10:34  Memory_of_winter  阅读(137)  评论(0编辑  收藏  举报