CF343D Water Tree

$ color{#0066ff}{ 题目描述 }$

疯狂科学家Mike培养了一颗有根树,由n个节点组成。每个节点是一个要么装满水要么为空的贮水容器. 树的节点用1~n编号,其中根节点为1.对于每个节点的容器,其子节点的容器均在这一容器下方,并且每个节点都由一根可以向下流水的管道与其子节点连接. Mike想要对这棵树做以下操作:

将节点v注满水. 这样v和其子节点都会充满水.
将节点v置空. 这样v及其祖先节点(从v到根节点的路径)都会被置空.
查询当前节点v是否充满水.

初始时,所有节点都为空. Mike已经制定好了他的操作顺序. 在对树进行实验前,他决定先模拟一下操作. 请你帮助Mike得出他操作后的结果.

(color{#0066ff}{输入格式})

第一行为一个整数n(1<=n<=500000),为树的节点数;
下面的n-1行为两个空格隔开的整数ai,bi(1<=ai, bi<=n),为树的边;
下一行为一个整数q(1<=q<=500000),为操作数;接下来q行,两个空格隔开的整数ci(1<=ci<=3),vi(1<=vi<=n),其中ci为操作类型(已给出),vi为被操作的节点.
这意味着给出的图为一棵树.

(color{#0066ff}{输出格式})

对于每一次操作3,如果节点v充满水,单独输出一行1,如果节点v为空,单独输出一行0. 按照操作输入的顺序输出.

(color{#0066ff}{输入样例})

5
1 2
5 1
2 3
4 2
12
1 1
2 3
3 1
3 2
3 3
3 4
1 2
2 4
3 1
3 3
3 4
3 5

(color{#0066ff}{输出样例})

0
0
0
1
0
1
0
1

(color{#0066ff}{数据范围与提示})

none

(color{#0066ff}{题解})

一个是树链操作,一个是子树操作,直接树剖,线段树甚至不用upd,因为不用维护任何东西。。

#include<bits/stdc++.h>
#define LL long long
LL in() {
	char ch; LL x = 0, f = 1;
	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
	return x * f;
}
const int maxn = 5e5 + 10;
struct Tree {
protected:
	struct node {
		node *ch[2];
		int l, r, val, tag;
		node(int l = 0, int r = 0, int val = 0, int tag = -1): l(l), r(r), val(val), tag(tag) {}
		void trn(int v) { tag = val = v; }
		void dwn() {
			if(!(~tag)) return;
			ch[0]->trn(tag), ch[1]->trn(tag);
			tag = -1;
		}
		int mid() { return (l + r) >> 1; }
	}*root;
	void build(node *&o, int l, int r) {
		o = new node(l, r, 0, -1);
		if(l == r) return;
		int mid = (l + r) >> 1;
		build(o->ch[0], l, mid);
		build(o->ch[1], mid + 1, r);
	}
	void lazy(node *o, int l, int r, int val) {
		if(l <= o->l && o->r <= r) return o->trn(val);
		o->dwn();
		if(l <= o->mid()) lazy(o->ch[0], l, r, val);
		if(r > o->mid()) lazy(o->ch[1], l, r, val);
	}
	int query(node *o, int pos) {
		if(o->l == o->r) return o->val;
		o->dwn();
		if(pos <= o->mid()) return query(o->ch[0], pos);
		else return query(o->ch[1], pos);
	}
public:
	void lazy(int l, int r, int val) { lazy(root, l, r, val); }
	int query(int pos) { return query(root, pos); }
	void build(int l, int r) { build(root, l, r); }
}s;
struct node {
	int to;
	node *nxt;
	node(int to = 0, node *nxt = NULL): to(to), nxt(nxt) {}
};
node *head[maxn];
int dep[maxn], siz[maxn], top[maxn], fa[maxn];
int dfn[maxn], nfd[maxn], son[maxn], cnt;
void add(int from, int to) {
	head[from] = new node(to, head[from]); 
}
void dfs1(int x, int f) {
	dep[x] = dep[fa[x] = f] + (siz[x] = 1);
	for(node *i = head[x]; i; i = i->nxt) {
		if(i->to == f) continue;
		dfs1(i->to, x);
		siz[x] += siz[i->to];
		if(!son[x] || siz[i->to] > siz[son[x]]) son[x] = i->to;
	}
}
void dfs2(int x, int t) {
	top[nfd[dfn[x] = ++cnt] = x] = t;
	if(son[x]) dfs2(son[x], t);
	for(node *i = head[x]; i; i = i->nxt) 
		if(!dfn[i->to]) 
			dfs2(i->to, i->to);
}
void up(int x) {
	for(; top[x]; x = fa[top[x]]) s.lazy(dfn[top[x]], dfn[x], 0);
}
int main() {
	int n = in();
	int x, y;
	for(int i = 1; i < n; i++) x = in(), y = in(), add(x, y), add(y, x);
	dfs1(1, 0), dfs2(1, 1), s.build(1, n);
	for(int T = in(); T --> 0;) {
		x = in(), y = in();
		if(x == 1) s.lazy(dfn[y], dfn[y] + siz[y] - 1, 1);
		if(x == 2) up(y);
		if(x == 3) printf("%d
", s.query(dfn[y]));
	}
	return 0;

}

原文地址:https://www.cnblogs.com/olinr/p/10460932.html