題目鏈接
題意:現在有一棵以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;
}