zoukankan      html  css  js  c++  java
  • [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
    ", count(tmp));
    		} else {
    			scanf("%d
    ", &y);
    			add(1, 1, n, dfn[x], dfn_o[x], 1ll << y - 1);
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    [bzoj4239]巴士走读
    [bzoj1146]网络管理
    [luogu3292]幸运数字
    [51nod1597]有限背包计数问题
    [bzoj2654]tree
    [bzoj2668]交换棋子
    [bzoj3173]最长上升子序列
    [hdu6715]算术
    [bzoj3784]树上的路径
    [bzoj1221]软件开发
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9479995.html
Copyright © 2011-2022 走看看