Description

Translated by @Nishikino_Maki from Luogu
行吧是我翻的

  • Mad scientist Mike has constructed a rooted tree, which consists of n 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 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:
  1. Fill vertex v with water. Then v and all its children are filled with water.
  2. Empty vertex v . Then v and all its ancestors are emptied.
  3. 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.

  • 疯狂科学家Mike培养了一颗有根树,由n个节点组成。每个节点是一个要么装满水要么为空的贮水容器. 树的节点用1~n编号,其中根节点为1.对于每个节点的容器,其子节点的容器均在这一容器下方,并且每个节点都由一根可以向下流水的管道与其子节点连接. Mike想要对这棵树做以下操作:

  1. 将节点v注满水. 这样v和其子节点都会充满水.
  2. 将节点v置空. 这样v及其祖先节点(从v到根节点的路径)都会被置空.
  3. 查询当前节点v是否充满水.
  • 初始时,所有节点都为空. Mike已经制定好了他的操作顺序. 在对树进行实验前,他决定先模拟一下操作. 请你帮助Mike得出他操作后的结果.

Input&Output

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.
  • 第一行为一个整数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为被操作的节点.
    这意味着给出的图为一棵树.

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.
  • 对于每一次操作3,如果节点v充满水,单独输出一行1,如果节点v为空,单独输出一行0. 按照操作输入的顺序输出.

Sample

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

Solution

  • 本题我们可以考虑将树形结构转为线性结构,通过DFS序记录每个节点进入和退出的时间,则区间[ intime[v], outtime[v] ]就代表线段上从v到v的所有子节点.
  • 如何维护?对于操作1,我们要对子树区间进行区间增加操作,对于操作2,也有类似的操作;操作3是查询操作,再加上上文中记录的线性结构,可以想到用线段树来维护.
  • 下面解释一些细节:
  1. 操作1,可以对区间实现整体加和操作,线段树的函数实现不再赘述。需要注意的是,对于节点的和,应当执行sum=length,而不应该执行+=操作,否则可能出现节点上的数字大于1的情况.
  2. 操作2,需要对节点及其到根节点的路径置为0,但我们没有记录路径,相应的修改比较麻烦,我们可以考虑先进行单点修改。
    为什么单点修改?
  • 我们可以对每个节点进行query操作,若结果<length,则意味着子节点中一定存在0,此时将其父节点置为0,因此单点修改可以对其祖先产生影响.从而保证了沿路径所有节点都可以在其子节点被访问时被修改.
  1. 查询时,若子节点中有0,则该节点为0.若子节点全为1,则该节点为1.
    初始状态如何处理?
  • 初始时,所有节点全为0,但这并不影响节点的状态,如果一个节点的子节点中有0,说明该子节点没有被修改过,因此我们查询的节点也一定没有被修改过.
  1. 关于lazy tag
  • 我们可以定义lazy的三种状态,0,1,-1,在pushdown时,如果遇到-1,代表没有操作,退出;对于另外两种状态,将子节点的sum值置为lazy*length即可.
  • 其他的一些操作大体和线段树类似.

  • 代码如下:

    #include<iostream>
    #include<cstdio>
    #define maxn 500010
    using namespace std;
    struct edge{
    int to,nxt;
    edge(){to=0;nxt=0;}
    }e[maxn<<1];
    struct node{
    int sum;
    int lazy;
    int l,r;
    int lc,rc;
    node()
    {
        lazy=-1;
        lc=rc=-1;
    }
    };
    int link[maxn],edgenum,itime[maxn],otime[maxn],fa[maxn];
    int n,op,ed,q,c,v;
    int dfscnt;
    void add(int bgn,int end)
    {
    edgenum++;
    e[edgenum].to=end;
    e[edgenum].nxt=link[bgn];
    link[bgn]=edgenum;
    }
    inline int rd()
    {
    int x=0;
    bool f=true;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')f=false;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return f?x:-x;
    }
    void dfs(int cur,int f)
    {
    itime[cur]=++dfscnt;
    for(int i=link[cur];i;i=e[i].nxt)
    {
        if(e[i].to==f)continue;
        fa[e[i].to]=cur;
        dfs(e[i].to,cur);
    }
    otime[cur]=dfscnt;
    }
    node tree[maxn<<1];
    int cnt;
    int rt=cnt++;
    void pushup(int cur)
    {
    int lc=tree[cur].lc,rc=tree[cur].rc;
    tree[cur].sum=tree[lc].sum+tree[rc].sum;
    tree[cur].l=tree[lc].l;
    tree[cur].r=tree[rc].r;
    }
    void pushup2(int cur)
    {
    int lc=tree[cur].lc,rc=tree[cur].rc;
    tree[cur].sum=tree[lc].sum+tree[rc].sum;
    }
    void pushdown(int cur)
    {
    if(tree[cur].lazy==-1)return;
    int lc=tree[cur].lc;
    int rc=tree[cur].rc;
    tree[lc].sum=tree[cur].lazy*(tree[lc].r-tree[lc].l+1);
    tree[rc].sum=tree[cur].lazy*(tree[rc].r-tree[rc].l+1);
    tree[lc].lazy=tree[cur].lazy;
    tree[rc].lazy=tree[cur].lazy;
    tree[cur].lazy=-1;
    }
    void build(int l,int r,int cur){
    if(l==r){
        tree[cur].sum=0;
        tree[cur].l=tree[cur].r=l;
        return;
    }
    int mid=(l+r)>>1;
    tree[cur].lc=cnt++;
    tree[cur].rc=cnt++;
    build(l,mid,tree[cur].lc);
    build(mid+1,r,tree[cur].rc);
    pushup(cur);
    }
    void upd(int l,int r,int x,int cur)
    {
    if(tree[cur].l>=l&&tree[cur].r<=r)
    {
        tree[cur].sum=x*(tree[cur].r-tree[cur].l+1);
        tree[cur].lazy=x;
        return;
    }
    pushdown(cur);
    int mid=(tree[cur].l+tree[cur].r)>>1;
    if(l<=mid)upd(l,r,x,tree[cur].lc);
    if(r>mid)upd(l,r,x,tree[cur].rc);
    pushup2(cur);
    }
    int query(int l,int r,int cur)
    {
    if(tree[cur].l>=l&&tree[cur].r<=r)
        return tree[cur].sum;
    pushdown(cur);
    int mid=(tree[cur].l+tree[cur].r)>>1;
    int tot=0;
    if(l<=mid)tot+=query(l,r,tree[cur].lc);
    if(r>mid)tot+=query(l,r,tree[cur].rc);
    return tot;
    }
    int main()
    {
    n=rd();
    for(int i=1;i<n;++i){
        op=rd();
        ed=rd();
        add(op,ed);
        add(ed,op);
    }
    dfs(1,0);
    build(1,n,rt);
    q=rd();
    for(int i=1;i<=q;++i){
        c=rd();
        if(c==1){
            v=rd();
            int l=itime[v];
            int r=otime[v];
            if(query(l,r,rt)<r-l+1&&v!=1)upd(itime[fa[v]],itime[fa[v]],0,rt);
            upd(itime[v],otime[v],1,rt);
        }
        else if (c==2){
            v=rd();
            upd(itime[v],itime[v],0,rt);
        }
        else if(c==3){
            v=rd();
            int l=itime[v];
            int r=otime[v];
            if(query(l,r,rt)<r-l+1)printf("0\n");
            else printf("1\n");
        }
    }
    return 0;
    } 

Codeforces 343D WaterTree - 线段树, DFS序的更多相关文章

  1. Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序

    题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s   内存限制:512.0MB    总提交次数:196   AC次数:65   平均分: ...

  2. BZOJ_3252_攻略_线段树+dfs序

    BZOJ_3252_攻略_线段树+dfs序 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏< ...

  3. 【XSY2534】【BZOJ4817】树点涂色 LCT 倍增 线段树 dfs序

    题目大意 ​ Bob有一棵\(n\)个点的有根树,其中\(1\)号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜 ...

  4. 【bzoj4817】树点涂色 LCT+线段树+dfs序

    Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...

  5. S - Query on a tree HDU - 3804 线段树+dfs序

    S - Query on a tree HDU - 3804   离散化+权值线段树 题目大意:给你一棵树,让你求这棵树上询问的点到根节点直接最大小于等于val的长度. 这个题目和之前写的那个给你一棵 ...

  6. HDU 5692 线段树+dfs序

    Snacks Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Sub ...

  7. Codeforces 343D Water Tree(DFS序 + 线段树)

    题目大概说给一棵树,进行以下3个操作:把某结点为根的子树中各个结点值设为1.把某结点以及其各个祖先值设为0.询问某结点的值. 对于第一个操作就是经典的DFS序+线段树了.而对于第二个操作,考虑再维护一 ...

  8. Codeforces 571D - Campus(并查集+线段树+DFS 序,hot tea)

    Codeforces 题目传送门 & 洛谷题目传送门 看到集合的合并,可以本能地想到并查集. 不过这题的操作与传统意义上的并查集不太一样,传统意义上的并查集一般是用来判断连通性的,而此题还需支 ...

  9. Codeforces 877E - Danil and a Part-time Job 线段树+dfs序

    给一个有根树,1e5个节点,每个节点有权值0/.1,1e5操作:1.将一个点的子树上所有点权值取反2.查询一个点的子树的权值和   题解: 先深搜整颗树,用dfs序建立每个点对应的区间,等于把树拍扁成 ...

随机推荐

  1. cesium 显示北京时间

    cesium用的JulianDate:代表天文朱利安时间,用的是世界协调时,比北京时间晚8个小时,所以在源代码中给默认的时间格式加上8小时. 应该会有更好的办法,希望有大神可以告诉我!!!!!!!!! ...

  2. selenium 基础(一)

    selenium安装 pip install selenium selenium操作浏览器原理 早期selenium 1.0 用的selenium RC, 后来selenum2集合了selenium1 ...

  3. python web开发-flask中消息闪现flash的应用

    Flash中的消息闪现,在官方的解释是用来给用户做出反馈.不过实际上这个功能只是一个记录消息的方法,在某一个请求中记录消息,在下一个请求中获取消息,然后做相应的处理,也就是说flask只存在于两个相邻 ...

  4. 笔记:Spring Cloud Eureka 高可用注册中心

    在微服务架构这样的分布式环境中,我们需要充分考虑发生故障的情况,所以在生产环境中必须对各个组件进行高可用部署,对与微服务和服务注册中心都需要高可用部署,Eureka 高可用实际上就是将自己作为服务向其 ...

  5. Docker(四):Docker 三剑客之 Docker Compose

    前两篇文章我们介绍了 Dockerfile 的使用Docker(二):Dockerfile 使用介绍,我们知道使用一个 Dockerfile 模板文件可以定义一个单独的应用容器,如果需要定义多个容器就 ...

  6. Java ORM Hibernate 入门笔记

    一.下载 官网地址:http://hibernate.org/ Hibernate下有ORM(关系型数据库).OGM(NoSQL数据库).Search(对象全文检索).Validator的工具. OR ...

  7. 关于js中promise的面试题。

    核心点promise在生命周期内有三种状态,分别是pending,fulfilled或rejected,状体改变只能是 pending-fulfilled,或者pending-rejected.而且状 ...

  8. Oracle安装11.2.0.4.180116补丁及如何检查数据库安装补丁

    最近做了一个安装11.2.0.4.180116补丁的实验,突然想起之前和同事讨论的一个问题:如何检查数据库安装补丁的版本,之前搜到的是去查dba_registry_history,有的说在操作系统中执 ...

  9. 爬虫(scrapy中调试文件)

    在项目setting同级目录下创建py文件,代码如下: from scrapy.cmdline import execute import sys import os sys.path.append( ...

  10. C语言中数据类型的取值范围

    C语言中数据类型的取值范围如下:char -128 ~ +127 (1 Byte)short -32767 ~ + 32768 (2 Bytes)unsigned short 0 ~ 65536 (2 ...