题目链接
题意:现在有一棵以1为根节点的树,每个节点有一个水池,现在有三种操作。
操作一:将v节点灌满水,然后他的所有子节点也将灌满水。
操作二:将v节点的水抽干,然后他的所有父节点的水也将被抽干。
操作三:查询某一个节点是否有水。
题解:这个题看数据肯定暴力不可行,现在我们先DFS序将树结构转化成线性结构,然后对子节点的操作就直接转化成了线段树的区间操作,现在灌满水的操作已经解决了。但是抽水是对父节点操作的,现在我们就可以在回溯的过程中来更改父节点的状态,因为每次我们都是从根节点开始递归,最后又要返回到根节点。所以我们可以先将子节点状态变了,然后在回溯的过程中改变父节点的状态,然后就是如何判断某个节点有没有水了,这个直接看代码。
#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int mod = 10007;
const int maxn = 5e5 + 5;
const int inf = 1e9;
const long long onf = 1e18;
#define me(a, b) memset(a,b,sizeof(a))
#define lowbit(x) x&(-x)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI 3.14159265358979323846
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int n, m;
int cnt, tot, head[maxn << 1];
int in[maxn], out[maxn];
int line[maxn << 2], lazy[maxn << 2], father[maxn];
bool flag = 0;
struct node {
int v, next;
} tree[maxn << 1];
void add_edge(int u, int v) {
tree[cnt] = node{v, head[u]};
head[u] = cnt++;
}
void DFS(int u, int fa) {
in[u] = ++tot;
father[u] = fa;
for (int i = head[u]; i != -1; i = tree[i].next) {
int v = tree[i].v;
if (v == fa)
continue;
DFS(v, u);
}
out[u] = tot;
}
void push_up(int rt) {
if (line[rt << 1] && line[rt << 1 | 1])
line[rt] = 1;
else
line[rt] = 0;
}
void push_down(int rt) {
if (lazy[rt]) {
lazy[rt << 1] = lazy[rt << 1 | 1] = lazy[rt];
line[rt << 1] = line[rt << 1 | 1] = lazy[rt];
lazy[rt] = 0;
}
}
void push_date(int L, int R, int x, int l, int r, int rt) {
if (L == 0)///除去根节点的情况
return;
if (L <= l && R >= r) {
if (!line[rt])
flag = 1;
line[rt] = x, lazy[rt] = x;
return;
}
push_down(rt);
int mid = (l + r) >> 1;
if (L <= mid)
push_date(L, R, x, lson);
if (R > mid)
push_date(L, R, x, rson);
push_up(rt);
}
void query(int L, int R, int l, int r, int rt) {
if (L <= l && R >= r) {
if (!line[rt])
flag = 1;
return;
}
push_down(rt);
int mid = (l + r) >> 1;
if (L <= mid)
query(L, R, lson);
if (R > mid)
query(L, R, rson);
}
void init() {
me(head, -1);
tot = cnt = 0;
}
void work() {
init();
scanf("%d", &n);
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
add_edge(u, v);
add_edge(v, u);
}
DFS(1, 0);
scanf("%d", &m);
while (m--) {
int opt, pos;
scanf("%d%d", &opt, &pos);
if (opt == 1) {
flag = 0;
push_date(in[pos], out[pos], 1, 1, n, 1);
if (flag)///在更新过程中,要是下面的子节点有些没水,说明那个子节点的所有父节点都没有水,但是现在把v节点
灌水,所以只需要更新现在灌水的父节点,将他变成没有水的状态。
push_date(in[father[pos]], in[father[pos]], 0, 1, n, 1);
} else if (opt == 2) {
push_date(in[pos], in[pos], 0, 1, n, 1);
} else {
flag = 0;
query(in[pos], out[pos], 1, n, 1);
if (flag)
puts("0");
else
puts("1");
}
}
}
int main() {
#ifndef ONLINE_JUDGE
// freopen("1.in", "r", stdin);
#endif
int t = 1, Case = 1;
// cin >> t;
while (t--) {
// printf("Case %d: ", Case++);
work();
}
return 0;
}