CodeForces 343D(树链剖分+线段树)

Mad scientist Mike has constructed a rooted tree, which consists of n vertices. Each vertex is a reservoir which can be either empty or filled with water.

The vertices of the tree are numbered from 1 to n with the root at vertex 1. For each vertex, the reservoirs of its children are located below the reservoir of this vertex, and the vertex is connected with each of the children by a pipe through which water can flow downwards.

Mike wants to do the following operations with the tree:

Fill vertex v with water. Then v and all its children are filled with water.
Empty vertex v. Then v and all its ancestors are emptied.
Determine whether vertex v is filled with water at the moment.
Initially all vertices of the tree are empty.
Mike has already compiled a full list of operations that he wants to perform in order. Before experimenting with the tree Mike decided to run the list through a simulation. Help Mike determine what results will he get after performing all the operations.

Input
The first line of the input contains an integer n (1 ≤ n ≤ 500000) — the number of vertices in the tree. Each of the following n - 1 lines contains two space-separated numbers ai, bi (1 ≤ ai, bi ≤ n, ai ≠ bi) — the edges of the tree.

The next line contains a number q (1 ≤ q ≤ 500000) — the number of operations to perform. Each of the following q lines contains two space-separated numbers ci (1 ≤ ci ≤ 3), vi (1 ≤ vi ≤ n), where ci is the operation type (according to the numbering given in the statement), and vi is the vertex on which the operation is performed.

It is guaranteed that the given graph is a tree.

Output
For each type 3 operation print 1 on a separate line if the vertex is full, and 0 if the vertex is empty. Print the answers to queries in the order in which the queries are given in the input.

Examples
input

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

output

0
0
0
1
0
1
0
1

题目大意:给出一棵树,支持三个操作:
1 x:将以x结点为根节点的子树都变为1
2 x:将结点x到根节点1的这一条链都变为0
3 x:判断结点x的值(0/1)

解题思路:这是一道树链剖分的板子题,我们在处理dfs序的时候先处理重链,那么我们就可以保证一棵子树是在一段连续的区间的同时,它的重链也在一段连续的区间内。然后我们执行操作1时就按照dfs序的方法去更新即可,执行操作2时,我们就路程中的一条链的更新就好啦,(因为保证一条重链的序号是连续的)。
代码:

#pragma GCC optimize(2)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <bitset>
#include <queue>
//#include 
#include <time.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define ls root<<1
#define rs root<<1|1
const int maxn = 5e5 + 7;
//std::mt19937 rnd(time(NULL));
struct edge
{
    int v, next;
} e[maxn << 1];
int head[maxn], cnt;
inline void add(int a,int b)
{
    e[++cnt] = edge{b, head[a]};
    head[a] = cnt;
}
/*
树链剖分
*/
int dfn[maxn], son[maxn], top[maxn], f[maxn], out[maxn], Size[maxn], tot;
void dfs1(int u,int fa)
{
    f[u] = fa, Size[u] = 1;
    son[u] = 0, Size[0] = 0;
    for (int i = head[u]; i;i=e[i].next){
        int v = e[i].v;
        if(v==fa)
            continue;
        dfs1(v, u);
        Size[u] += Size[v];
        if(Size[son[u]]<Size[v]){
            son[u] = v;
        }
    }
}
void dfs2(int u,int fa)
{
    if(u==0)
        return;
    dfn[u] = ++tot, top[u] = fa;
    dfs2(son[u], fa);
    for (int i = head[u]; i;i=e[i].next){
        int v = e[i].v;
        if(v==son[u] || v==f[u])
            continue;
        dfs2(v, v);
    }
    out[u] = tot;
}

/*
线段树维护
*/
struct tree
{
    int l, r, date, lazy;
} t[maxn << 2];
void build(int root,int l,int r)
{
    t[root].l = l, t[root].r = r;
    t[root].date = 0, t[root].lazy = -1;
    if(l==r)
        return;
    int mid = l + r >> 1;
    build(ls, l, mid);
    build(rs, mid + 1, r);
}
void pushdown(int root)
{
    if(t[root].lazy!=-1){
        t[ls].lazy = t[rs].lazy = t[root].lazy;
        t[ls].date = (t[ls].r - t[ls].l + 1) * t[root].lazy;
        t[rs].date = (t[rs].r - t[rs].l + 1) * t[root].lazy;
        t[root].lazy = -1;
    }
}
int query(int root,int k)
{
    if(t[root].l==t[root].r){
        return t[root].date;
    }
    pushdown(root);
    int mid = t[root].l + t[root].r >> 1;
    if(k<=mid)
        return query(ls, k);
    else
        return query(rs, k);
}
void update(int root,int l,int r,int k)
{
    if(t[root].l>=l && t[root].r<=r){
        t[root].date = k * (t[root].r - t[root].l + 1);
        t[root].lazy = k;
        return;
    }
    pushdown(root);
    int mid = t[root].r + t[root].l >> 1;
    if(l<=mid)
        update(ls, l, r, k);
    if(r>mid)
        update(rs, l, r, k);
}
void tupdate(int x)
{
    while(x!=1){
        update(1,dfn[top[x]],dfn[x],0);
        //printf("%lld %lld\n",top[x],x);
        x=top[x];
        x=f[x];
    }
    update(1,1,dfn[x],0);
}
void debug(int n)
{
    printf("\n");
    for (int i = 1; i <= n;i++){
        printf("%lld %lld\n", dfn[i], top[i]);
        //printf("%lld\n", son[i]);
    }
    printf("\n");
}
signed main()
{
    int n;
    scanf("%lld", &n);
    for (int i = 1; i < n;i++){
        int x, y;
        scanf("%lld%lld", &x, &y);
        add(x, y), add(y, x);
    }
    dfs1(1, 1), dfs2(1, 1);
    build(1, 1, n);
    //debug(n);
    int m;
    scanf("%lld", &m);
    while(m--){
        int op;
        scanf("%lld", &op);
        if(op==1){
            int x;
            scanf("%lld", &x);
            update(1, dfn[x], out[x], 1);
        }
        else if(op==2){
            int x;
            scanf("%lld", &x);
            tupdate(x);
        }
        else{
            int x;
            scanf("%lld", &x);
            printf("%lld\n", query(1, dfn[x]));
        }
    }
}

PS:回家很久啦,本来说好的回来就开始学,但是最近发生了很多事情,希望2020年可以更好。
武汉加油!湖北加油!四川加油!中国加油!

你可能感兴趣的:(数据结构,线段树,树链剖分)