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. curl post请求总是返回417错误

    在进行post请求的时候, curl总是返回417错误 在使用curl做POST的时候, 当要POST的数据大于1024字节的时候, curl并不会直接就发起POST请求, 而是会分为俩步. 发送一个 ...

  2. 使用jitpack来获取github上的开源项目

    在开发中我们需要经常使用第三方依赖库,在构建工具Gradle或maven中声明依赖, 大部分使用的是maven中心仓库或者阿里云仓库等等,但是这样也存在一个问题,上述仓库的库虽然简单快捷好用,但并不是 ...

  3. Oracle服务器和客户端的安装和卸载

    Oracle 11g服务器与客户端的完全卸载方式与前些版本有了改变: 一.卸载前准备: 开始->设置->控制面板->管理工具->服务 停止所有Oracle服务. 二.批处理卸载 ...

  4. hibernate框架学习笔记2:配置文件详解

    实体类: package domain; public class Customer { private Long cust_id; private String cust_name; private ...

  5. 连接数据后,当执行查询语句报错:ORA-01219: 数据库未打开: 仅允许在固定表/视图中查询

    参考博客:http://blog.csdn.net/lanchengxiaoxiao/article/details/40982771 1.在cmd窗口通过sqlplus连接数据库 C:\Users\ ...

  6. Android开发简易教程

    Android开发简易教程 Android 开发因为涉及到代码编辑.UI 布局.打包等工序,有一款好用的IDE非常重要.Google 最早提供了基于 Eclipse 的 ADT 作为开发工具,后来在2 ...

  7. beat冲刺计划安排

    1. 团队成员 组长:郭晓迪 组员:钟平辉 柳政宇 徐航 曾瑞 2. 主要计划安排如下: 3. 详细日程任务安排

  8. Archlinux无线联网教程

    本人是学生党,故对于有线方式不甚了解,学校里一般使用mentohust用动态IP方式联网,或者直接连接wifi,这里介绍无线联网的一些方式,主要包括公共wifi和带有WEP或者WPA或者WPA2PSK ...

  9. 201621123068 作业07-Java GUI编程

    1. 本周学习总结 1.1 思维导图:Java图形界面总结 2.书面作业 1. GUI中的事件处理 1.1 写出事件处理模型中最重要的几个关键词. 注册.事件.事件源.监听 1.2 任意编写事件处理相 ...

  10. 201621123031 《Java程序设计》第6周学习总结

    作业06-接口.内部类 1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图或相关笔记,对面向对象思想进行一个总结. 注1:关键词与内容不求多 ...