CodeForces - 343D Water Tree (DFS序+線段樹)

題目鏈接

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章