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

操作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. Codeforces 282E Sausage Maximization(字典树)

    题目链接:282E Sausage Maximization 题目大意:给定一个序列A.要求从中选取一个前缀,一个后缀,能够为空,当时不能重叠.亦或和最大. 解题思路:预处理出前缀后缀亦或和,然后在字 ...

  2. Processing.js

    Processing.js Processing.js 1.4.1 released!

  3. 一个跨平台的 C++ 内存泄漏检测器

    2004 年 3 月 01 日 内存泄漏对于C/C++程序员来说也可以算作是个永恒的话题了吧.在Windows下,MFC的一个很有用的功能就是能在程序运行结束时报告是否发生了内存泄漏.在Linux下, ...

  4.   PS2: 这篇文章中的图片绘图工具使用的是Dia (sudo apt-get install dia)。据说yEd也很不错。

    SBCL编译过程 - O.Nixie的专栏 - 博客频道 - CSDN.NET PS2: 这篇文章中的图片绘图工具使用的是Dia (sudo apt-get install dia).据说yEd也很不 ...

  5. UpdataData

    MFC中有一个UpdataData函数,有二个参数:TRUE和FLASE,二个参数什么时候用, 开始的时候我也迷糊,后来才发现: UpdataData(TRUE):是把控件上的值刷新到变量中: Upd ...

  6. poj 2409+2154+2888(Burnside定理)

    三道burnside入门题: Burnside定理主要理解置换群置换后每种不动点的个数,然后n种不动点的染色数总和/n为answer. 对于旋转,旋转i个时不动点为gcd(n,i). 传送门:poj ...

  7. Linux Shell 函数返回值

    Shell函数返回值,常用的两种方式:return,echo 1) return 语句 shell函数的返回值,可以和其他语言的返回值一样,通过return语句返回. 示例: #!/bin/sh fu ...

  8. BZOJ 1367([Baltic2004]sequence-左偏树+中位数贪心)

    1367: [Baltic2004]sequence Time Limit: 20 Sec   Memory Limit: 64 MB Submit: 521   Solved: 159 [ Subm ...

  9. 基于libevent, libuv和android Looper不断演进socket编程 - 走向架构师之路 - 博客频道 - CSDN.NET

    基于libevent, libuv和android Looper不断演进socket编程 - 走向架构师之路 - 博客频道 - CSDN.NET 基于libevent, libuv和android L ...

  10. CoreJava_Collection接口add有一个返回值!

        今天讨论与朋友小知识,我发现很多人不知道collection接口定义add方法返回的值,我们所有的工作很多年Java职工.不熟悉的公共接口,使自己成为在细节上的麻烦.一个小采访这让我想起,当我 ...