给定一棵树,初始时树为空

操作1,往某个结点注水,那么该结点的子树都注满了水

操作2,将某个结点的水放空,那么该结点的父亲的水也就放空了

操作3,询问某个点是否有水

我们将树进行dfs, 生成in[u], 访问结点u的时间戳,out[u],离开结点u的时间戳

每个结点的in值对应在线段树中的区间的一点

那么对于操作1, 只要将区间[in[u],out[u]] 的值都改为1, 但是如果区间[in[u],out[u]] 原先存在为0的点,那么父区间肯定是空的,这个操作不能

改变父区间的状态,所以需要将in[fa[u]]置为0,

对于操作2,只要将in[u] 置为0就行了

对于操作3,只要区间[in[u],out[u]]内不存在为0的点,那么点u就是有水的

 #include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
const int INF = <<;
/*
我们对树进行dfs,求出dfs序列 in[] 和out[] 用线段树维护这个序列
操作1就是将[in[b],out[b]]区间内的点都变为1 , 如果区间内存在0,那么要将b的父结点更新为0,因为虽然更新了[in[b],out[b]],但是祖先不会变
操作2就是将点in[b]置为0
操作3就是看区间[in[b],out[b]] 所以不仅可以将树进行树链剖分,然后用线段树维护
还可以用线段树维护树的dfs序列
*/
const int N = + ;
int in[N], out[N], num, fa[N];
int tree[N * ], laze[N * ];
vector<int> g[N];
void dfs(int u)
{
in[u] = ++num;
for (int i = ; i < g[u].size(); ++i)
{
int v = g[u][i];
if (v != fa[u])
{
fa[v] = u;
dfs(v);
}
}
out[u] = num;
}
void pushDown(int rt)
{
if (laze[rt]==)
{
tree[rt << ] = tree[rt << | ] = laze[rt << ] = laze[rt << | ] = ;
laze[rt] = ;
}
}
void pushUp(int rt)
{
if (tree[rt << ] == || tree[rt << | ] == )
tree[rt] = ;
else
tree[rt] = ;
}
bool flag = false;
void update(int l, int r, int rt, int L, int R, int val)
{
pushDown(rt);
if (L<=l && R>=r)
{
if (tree[rt] == )
flag = true;
tree[rt] = val;
laze[rt] = val;
return;
}
int mid = (l + r) >> ;
if (L <= mid)
update(l, mid, rt << , L, R, val);
if (R > mid)
update(mid + , r, rt << | , L, R, val);
pushUp(rt);
} void query(int l, int r, int rt, int L, int R)
{
pushDown(rt);
if (L<=l && R>=r)
{
//区间内有一个是0,那么所访问的点(根)就是0
if (tree[rt] == )
flag = false;
return;
}
int mid = (l + r) >> ;
if (L <= mid)
query(l, mid, rt << , L, R);
if (R > mid)
query(mid + , r, rt << | , L, R);
pushUp(rt);
}
int main()
{
//freopen("d:/in.txt", "r", stdin);
int n, q, a, b,x, y;
scanf("%d", &n);
for (int i = ; i < n; ++i)
{
scanf("%d%d", &a, &b);
g[a].push_back(b);
g[b].push_back(a);
}
fa[] = ;
dfs();
scanf("%d", &q);
while (q--)
{
scanf("%d%d", &a, &b);
if (a == )
{
flag = false;
//将区间内的点都置为1
update(, n, , in[b], out[b],);
//如果区间内存在0的点,那么fa[b]肯定为空,
if (flag&&fa[b]!=)
{
update(, n, , in[fa[b]],in[fa[b]],);
}
}
else if (a == )
{
update(, n, , in[b],in[b],);
}
else
{
flag = true;
query(,n, , in[b], out[b]);
if (flag)
printf("1\n");
else
printf("0\n");
}
}
return ;
}

CodeForces 343D 线段树维护dfs序的更多相关文章

  1. CF877E Danil and a Part-time Job 线段树维护dfs序

    \(\color{#0066ff}{题目描述}\) 有一棵 n 个点的树,根结点为 1 号点,每个点的权值都是 1 或 0 共有 m 次操作,操作分为两种 get 询问一个点 x 的子树里有多少个 1 ...

  2. P3703 [SDOI2017]树点涂色 LCT维护颜色+线段树维护dfs序+倍增LCA

    \(\color{#0066ff}{ 题目描述 }\) Bob有一棵\(n\)个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点 ...

  3. bzoj 3779: 重组病毒【LCT+线段树维护dfs序】

    %.8lf会WA!!%.8lf会WA!!%.8lf会WA!!要%.10lf!! 和4817有点像,但是更复杂. 首先对于操作一"在编号为x的计算机中植入病毒的一个新变种,在植入一个新变种时, ...

  4. BZOJ 4817 [SDOI2017]树点涂色 (LCT+线段树维护dfs序)

    题目大意:略 涂色方式明显符合$LCT$里$access$操作的性质,相同颜色的节点在一条深度递增的链上 用$LCT$维护一个树上集合就好 因为它维护了树上集合,所以它别的啥都干不了了 发现树是静态的 ...

  5. 【HIHOCODER 1576】 子树中的最小权值(线段树维护DFS序)

    描述 给定一棵N个节点的树,编号1~N.其中1号节点是根,并且第i个节点的权值是Vi. 针对这棵树,小Hi会询问小Ho一系列问题.每次小Hi会指定一个节点x,询问小Ho以x为根的子树中,最小的权值是多 ...

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

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

  7. codeforces 877 E. Danil and a Part-time Job(线段树(dfs序))

    题目链接:http://codeforces.com/contest/877/problem/E 题解:显然一看就感觉要么树链剖分要么线段树+dfs序,题目要求的操作显然用线段树+dfs序就可以实现. ...

  8. 2018.11.01 NOIP训练 图论(线段树+倍增+dfs序)

    传送门 一道挺妙的题. 对于询问点(u,v),如右图所示,我们可以发现存在一个点m在u->v的路径中,m子树的点到u是最近的,m子树外到v是最近的.其中dis(u,m)=(dis(u,v)-1) ...

  9. Codeforces 343D 线段树

    题意:给你一颗以点1为根的数,有两种操作,一种是把x及其子树的所有点都灌满水,一种是把x及其所有祖先都放空水,一种是询问,问某个点里有没有水? 思路:看网上大多数是树剖,但实际上5e5的数据树剖还是有 ...

随机推荐

  1. bestcoder.hdu.edu.cn

    http://bestcoder.hdu.edu.cn/ Problem A 题目链接: http://bestcoder.hdu.edu.cn/contests/contest_showproble ...

  2. VC添加背景图片 的一种方法

    .如果程序是新建的对话框,要给其添加背景图片的步骤: 1)加入消息函数:afx_msg void OnPaint(); 2)BEGIN_MESSAGE_MAP(QueryDlg, CDialog) O ...

  3. Delphi 模拟网站验证码(酷,把随机文字写道图片上)

    function TfrmLabelPages.PwdImg(img: Timage): string; var I,j,k: Integer; vPoint: TPoint; vLeft: Inte ...

  4. Lucene.Net 2.3.1开发介绍 —— 三、索引(二)

    原文:Lucene.Net 2.3.1开发介绍 -- 三.索引(二) 2.索引中用到的核心类 在Lucene.Net索引开发中,用到的类不多,这些类是索引过程的核心类.其中Analyzer是索引建立的 ...

  5. Android读取网络图片

    本文是自己学习所做笔记,欢迎转载,但请注明出处:http://blog.csdn.net/jesson20121020 在android4.0之后,已不同意在主线程中进行网络请求操作了, 否则会出现N ...

  6. Js实现select联动,option从数据库中读取

    待要实现的功能:页面有两个select下拉列表,从第一个select中选择后,在第二个select中出现对应的列表选择,再从第二个select中选择后,在一个text中显示对应的信息.两个select ...

  7. Android 进行单元測试难在哪-part3

    原文链接 : HOW TO MAKE OUR ANDROID APPS UNIT TESTABLE (PT. 1) 原文作者 : Matthew Dupree 译文出自 : 开发技术前线 www.de ...

  8. WinMM.dll 函数汇总

    #include "MMSystem.h" auxGetDevCaps                  查询指定的辅助输出设备以确定其性能 auxGetNumDevs       ...

  9. RSA加密解密和读取公钥、私钥

    /// <summary>     /// RSA加密解密及RSA签名和验证    /// </summary>     public class RSADE    {    ...

  10. C语言笔记之结构体

    结构的本质是C语言的一种数据抽象,通俗的说,是基本数据类型的重组. 为什么要重组呢?由于基本数据类型不够用了.为什么不够用了呢?由于须要的信息类型太多了. 这是一个非常大的话题.信息本来是没有什么类型 ...