Codeforces 343D WaterTree - 线段树, DFS序

时间:2023-02-25 15:56:26

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&period; 树(张闻涛) 倍增LCA&comma;可持久化线段树&comma;DFS序

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

  2. BZOJ&lowbar;3252&lowbar;攻略&lowbar;线段树&plus;dfs序

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

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

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

  4. 【bzoj4817】树点涂色 LCT&plus;线段树&plus;dfs序

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

  5. S - Query on a tree HDU - 3804 线段树&plus;dfs序

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

  6. HDU 5692 线段树&plus;dfs序

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

  7. Codeforces 343D Water Tree(DFS序 &plus; 线段树)

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

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

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

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

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

随机推荐

  1. Webstorm&plus;Webpack&plus;echarts构建个性化定制的数据可视化图表&amp&semi;&amp&semi;两个echarts详细教程(柱状图,南丁格尔图)

    Webstorm+Webpack+echarts   ECharts 特性介绍 ECharts,一个纯 Javascript 的图表库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(I ...

  2. 使用 Wireshark 调试 HTTP&sol;2 流量

    https://imququ.com/post/http2-traffic-in-wireshark.html

  3. Ant、Maven、Gradle

    android Gradle project http://www.ibm.com/developerworks/cn/opensource/os-cn-gradle/ http://www.voge ...

  4. Shell教程1&ZeroWidthSpace;-第一个Shell脚本

    打开文本编辑器,新建一个文件,扩展名为sh(sh代表shell),扩展名并不影响脚本执行,见名知意就好,如果你用php写shell 脚本,扩展名就用php好了.输入一些代码: #!/bin/bash ...

  5. Unity3d &plus; NGUI 多分辨率适应

    更多型号适合的移动终端 现在我们要介绍的<链战争>游戏改编方法,这种适应方法UI这是一个基本维度,背景是一个基本的尺寸.背景比UI没有实际影响某一部分的额外部分,这样就避免了适应iPhon ...

  6. VC&plus;&plus; 响应回车键的2种方法

    众所周知,VC++响应回车键经常用的方法是利用 BOOL PreTranslateMessage(MSG* pMsg) 截取回车键消息,如: if (pMsg->message == WM_KE ...

  7. WebFetch 是无依赖极简网页爬取组件

    WebFetch 是无依赖极简网页爬取组件,能在移动设备上运行的微型爬虫. WebFetch 要达到的目标: 没有第三方依赖jar包 减少内存使用 提高CPU利用率 加快网络爬取速度 简洁明了的api ...

  8. ios 概况了解

    iOS的系统架构分为四个层次:( iOS是基于UNIX内核,android是基于Linux内核) 核心操作系统层(Core OS layer).核心服务层(Core Services layer).媒 ...

  9. Android 解决通过自定义设置打开热点后手机搜索不到热点的问题。

    开发过程中出现了通过自定义设置打开热点后手机搜索不到热点的问题. 后来通过观看  /data/misc/wifi  目录下的  hostapd.conf  文件,发现是 interface=ap0 d ...

  10. SAML2&period;0 SP端处理

    sso response解析 import java.io.ByteArrayInputStream; import java.io.InputStream; import java.security ...