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;
}

 

©️2020 CSDN 皮肤主题: 创作都市 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值