Codeforces 343D 线段树

Posted pkgunboat

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 343D 线段树相关的知识,希望对你有一定的参考价值。

题意:给你一颗以点1为根的数,有两种操作,一种是把x及其子树的所有点都灌满水,一种是把x及其所有祖先都放空水,一种是询问,问某个点里有没有水?

思路:看网上大多数是树剖,但实际上5e5的数据树剖还是有点慌的。。。我只用了线段树。我们发现,只要一个点被清空之后,如果没有灌水,那么这个点将一直是空的。同理,如果这个点被灌满水后一直不是空的,那么它将一直是满的,所以,这个点的状态实际取决于离查询时间最近的是放水还是灌水。我们可以用线段树来维护这个,我们首先来维护灌水时间,这个在dfs序后用线段树的区间操作,很好完成。那么放水呢?我们换个思维,清空这个点及其祖先,反过来说,如果这个点被清空了,那么一定是它的子树中的某个点被清空了,所以我们可以用线段树查询它被清空的最晚时间,与之前的操作比较,如果清空操作较晚,那么这个点就是空的,否则就是满的。

代码:

#include <bits/stdc++.h>
#define LL long long
#define INF 0x3f3f3f3f
#define db double
#define pii pair<int, int>
#define ls (x << 1)
#define rs ((x << 1) | 1)
using namespace std;
const int maxn = 500010;
int a[maxn];
int dfn[maxn], tot, sz[maxn];
vector<int> G[maxn];
struct node {
	int add, del;
	int lz;
};
node tr[maxn * 4];
void add(int x, int y) {
	G[x].push_back(y);
	G[y].push_back(x);
}
void pushup(int x) {
	tr[x].del = max(tr[ls].del, tr[rs].del);
}
void maintain(int x, int y) {
	tr[x].add = y;
	tr[x].lz = y;
}
void pushdown(int x) {
	if(tr[x].lz != -1) {
		maintain(ls, tr[x].lz);
		maintain(rs, tr[x].lz);
		tr[x].lz = -1;
	}
}
void build(int x, int l, int r) {
	if(l == r) {
		tr[x].lz = -1;
		return;
	}
	int mid = (l + r) >> 1;
	build(ls, l, mid);
	build(rs, mid + 1, r);
	pushup(x);
}
void add1(int x, int l, int r, int ql ,int qr, int val) {
	if(l >= ql && r <= qr) {
		maintain(x, val);
		return;
	}
	pushdown(x);
	int mid = (l + r) >> 1;
	if(ql <= mid) add1(ls, l, mid, ql, qr, val);
	if(qr > mid) add1(rs, mid + 1, r, ql, qr, val);
	pushup(x);
}
void add2(int x, int l, int r, int pos, int val) {
	if(l == r) {
		tr[x].del = val;
		return;
	}
	pushdown(x);
	int mid = (l + r) >> 1;
	if(pos <= mid) add2(ls, l, mid, pos, val);
	else add2(rs, mid + 1, r, pos, val);
	pushup(x);
}
int query1(int x, int l, int r, int pos) {
	if(l == r) return tr[x].add;
	pushdown(x);
	int mid = (l + r) >> 1;
	if(pos <= mid) return query1(ls, l, mid, pos);
	else return query1(rs, mid + 1, r, pos);
}
int query2(int x, int l, int r, int ql, int qr) {
	if(l >= ql && r <= qr) return tr[x].del;
	pushdown(x);
	int mid = (l + r) >> 1;
	int ans = 0;
	if(ql <= mid) ans = max(ans, query2(ls, l, mid, ql, qr));
	if(qr > mid) ans = max(ans, query2(rs, mid + 1, r, ql, qr));
	return ans;
} 
void dfs(int x, int fa) {
	dfn[x] = ++tot;
	sz[x] = 1;
	for (auto y : G[x]) {
		if(y == fa) continue;
		dfs(y, x);
		sz[x] += sz[y];
	}
}
int main() {
	int n, m, x, y;
	scanf("%d", &n);
	for (int i = 1; i < n; i++) {
		scanf("%d%d", &x, &y);
		add(x, y);
	}
	dfs(1, -1);
	build(1, 1, n);
	scanf("%d", &m);
	for(int i = 1; i <= m; i++) {
		scanf("%d%d", &x, &y);
		if(x == 1) {
			add1(1, 1, n, dfn[y], dfn[y] + sz[y] - 1, i);
		} else if(x == 2) {
			add2(1, 1, n, dfn[y], i);
		} else {
			int tmp1 = query1(1, 1, n, dfn[y]), tmp2 = query2(1, 1, n, dfn[y], dfn[y] + sz[y] - 1);
			if(tmp1 <= tmp2) printf("0\n");
			else printf("1\n");
		}
	}
}

  

以上是关于Codeforces 343D 线段树的主要内容,如果未能解决你的问题,请参考以下文章

codeforces 343D Water Tree 树链剖分 dfs序 线段树 set

Codeforces 343D Water Tree & 树链剖分教程

Codeforces 343D Water Tree

CoderForces343D:Water Tree(dfs序+线段树&&特殊处理)

CF343D Water Tree 树链剖分

CodeForces 343D water tree(树链剖分)