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\n", s.query(dfn[y]));
    }
    return 0;

}

猜你喜欢

转载自www.cnblogs.com/olinr/p/10460932.html