【codeforces 620E】【dfs】【线段树 】【lazy】【子树区间修改,区间求和】

4 篇文章 0 订阅
1 篇文章 0 订阅

https://codeforces.com/problemset/problem/620/E

【题意】

子树区间修改,区间求和

【分析】先将树形结构通过dfs序转化为线性结构,子树的操作转化为线性区间上的操作,加个2进制ll存储val,lazy标记更新

【代码】

  好久没写线段树了,呜呜呜

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 1e6 + 6;
int c[maxn], pos[maxn];
vector<int>v[maxn];

//线段树部分----------------------------------------------------------
struct node {
	int l, r;
	ll val;
	int lazy;
	int mid(void) {
		return l + r >> 1;
	}
}tr[maxn<<2];

void pushDown(int p) {
	if (tr[p].lazy) {
		tr[p << 1].lazy = tr[p << 1 | 1].lazy = tr[p].lazy;
		tr[p << 1 | 1].val = tr[p << 1].val = 1LL << tr[p].lazy;
		tr[p].lazy = 0;
	}
}

void build(int p, int l,int r) {
	tr[p].l = l;
	tr[p].r = r;
	tr[p].lazy = 0;
	tr[p].val = 0;
	if (l == r) {
		tr[p].val = 1LL << c[pos[l]];
		return;
	}
	int mid = tr[p].mid();
	build(p << 1, l, mid);
	build(p << 1 | 1, mid + 1, r);
	tr[p].val = tr[p << 1].val | tr[p << 1 | 1].val;
}

void update(int p, int l, int r, int L, int R, int x) {
	if (L <= tr[p].l&&tr[p].r <= R) {
		tr[p].lazy = x;
		tr[p].val = 1LL << x;
		return;
	}
	pushDown(p);
	int mid = tr[p].mid();
	if (L <= mid)update(p << 1, l, mid, L, R, x);
	if (R > mid)update(p << 1 | 1, mid + 1, r, L, R, x);
	tr[p].val = tr[p << 1].val | tr[p << 1 | 1].val;
}

ll query(int p, int l, int r, int L,int R) {
	if (L <= l && r <= R) {
		return tr[p].val;
	}
	pushDown(p);
	int mid = tr[p].mid();
	ll res = 0;
	if (L <= mid)res |= query(p << 1, l, mid, L, R);
	if (R > mid)res |= query(p << 1 | 1, mid + 1, r, L, R);
	tr[p].val = tr[p << 1].val | tr[p << 1 | 1].val;
	return res;
}

//dfs部分---------------------------------------------------------------
int dfsL[maxn], dfsR[maxn];
int tot = 0;
//获得每个节点1->tot的编号
void dfs(int p, int f ) {//L,R表示一个子树的范围
	dfsL[p] = ++tot;
	pos[tot] = p;
	for (int q : v[p]) {
		if (q == f)continue;
		dfs(q, p);
	}
	dfsR[p] = tot;
}


int main() {
	int n, m;
	while (~scanf("%d%d", &n, &m)) {
		for (int i = 1; i <= n; i++) {
			scanf("%d", &c[i]);
			v[i].clear();
		}
		for (int i = 1; i < n; i++) {
			int x, y;
			scanf("%d%d", &x, &y);
			v[x].push_back(y);
			v[y].push_back(x);
		}
		dfs(1, 0);
		build(1, 1, n);
		while (m--) {
			int op;
			scanf("%d", &op);
			if (op == 1) {
				int v, x;
				scanf("%d%d", &v, &x);
				update(1, 1, n, dfsL[v], dfsR[v], x);
			}
			else {
				int v;
				scanf("%d", &v);
				ll ans = query(1, 1, n, dfsL[v], dfsR[v]);
				printf("%d\n", bitset<1000>(ans).count());
			}
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值