D. Water Tree

time limit per test:4 seconds
memory limit per test:256 megabytes
input:standard input
output:standard output

Mad scientist Mike has constructed a rooted tree, which consists of 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 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.

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 aibi (1 ≤ ai, bi ≤ nai ≠ 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.

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.

Examples

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

这颗树具有一个重要的特性,当一个点是 0 的时候,这个点的全部祖先一定都是 0;一点是 1,这个点的全部子孙都是 1。

利用这个性质,如果我们要把一个节点以及他的祖先都变成 0,我们只要把这个点标记成 0 就可以了——因为这样就包含了所有的操作信息。这种观点下,再看这三种操作。

  1. u 点以及 u 点的所有子孙都赋值为 1:这个时候应该先看一看子孙有没有 0,如果有 0,那么说明 u 的祖先都是应该是 0 但是还没表现出来。所以我们把 u 的父亲标记成 0。这之后,我们再把所有的子孙赋值成 1。
  2. u 点以及 u 点的所有祖先都赋值为 0:u 标记成 0;
  3. 查询一个点 u 的值:u 以及 u 的所以子孙的标记都不是 0,u 才真正的是 1。

这样一看,好开心,这三种操作都变成了树上的单点修改或者是一整个子树的整体修改。这个解决起来就很套路了,我们把树按照 dfs 序展开,就变成了线段树连续区间修改的问题。

 //2017-09-01
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lson (id<<1)
#define rson ((id<<1)|1) using namespace std; const int N = ; int head[N], tot;
struct Edge{
int to, next;
}edge[N<<]; void init(){
tot = ;
memset(head, -, sizeof(head));
} void add_edge(int u, int v){
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
} int in[N], out[N], fa[N], cnt;
void dfs(int u, int father){
in[u] = ++cnt;
for(int i = head[u]; i != -; i = edge[i].next){
int v = edge[i].to;
if(v != father){
fa[v] = u;
dfs(v, u);
}
}
out[u] = cnt;
} bool flag;
struct Node{
int l, r, value, lazy;
}tree[N<<]; void build(int id, int l, int r){
tree[id].l = l;
tree[id].r = r;
tree[id].value = ;
tree[id].lazy = ;
if(l == r)return;
int mid = (tree[id].l+tree[id].r)>>;
build(lson, l, mid);
build(rson, mid+, r);
} void push_up(int id){
if(tree[lson].value && tree[rson].value)tree[id].value = ;
else tree[id].value = ;
} void push_down(int id){
if(tree[id].lazy){
tree[lson].value = tree[rson].value = tree[id].lazy;
tree[lson].lazy = tree[rson].lazy = tree[id].lazy;
tree[id].lazy = ;
}
} void update(int id, int l, int r, int op){
if(l == )return;
if(l <= tree[id].l && tree[id].r <= r){
if(tree[id].value == )flag = ;
tree[id].value = op;
if(op == )tree[id].lazy = op;
return;
}
push_down(id);
int mid = (tree[id].l+tree[id].r)>>;
if(l <= mid)update(lson, l, r, op);
if(r > mid)update(rson, l, r, op);
push_up(id);
} void query(int id, int l, int r){
if(l <= tree[id].l && tree[id].r <= r){
if(tree[id].value == )flag = ;
return;
}
push_down(id);
int mid = (tree[id].l+tree[id].r)>>;
if(l <= mid)query(lson, l, r);
if(r > mid)query(rson, l, r);
} int n, q; int main()
{
//freopen("inputF.txt", "r", stdin);
while(scanf("%d", &n) != EOF){
init();
int u, v;
for(int i = ; i < n-; i++){
scanf("%d%d", &u, &v);
add_edge(u, v);
add_edge(v, u);
}
fa[] = ;
cnt = ;
dfs(, );
build(, , n);
scanf("%d", &q);
while(q--){
scanf("%d%d", &u, &v);
if(u == ){
flag = ;
update(, in[v], out[v], );
if(!flag)update(, in[fa[v]], in[fa[v]], );
}else if(u == ){
update(, in[v], in[v], );
}else{
flag = ;
query(, in[v], out[v]);
if(flag)printf("1\n");
else printf("0\n");
}
}
} return ;
}

Codeforces343D(SummerTrainingDay06-F dfs序+线段树)的更多相关文章

  1. F - Change FZU - 2277 (DFS序+线段树)

    题目链接: F - Change FZU - 2277 题目大意: 题意: 给定一棵根为1, n个结点的树. 有q个操作,有两种不同的操作 (1) 1 v k x : a[v] += x, a[v ' ...

  2. 【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心

    3252: 攻略 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 339  Solved: 130[Submit][Status][Discuss] D ...

  3. 【XSY2667】摧毁图状树 贪心 堆 DFS序 线段树

    题目大意 给你一棵有根树,有\(n\)个点.还有一个参数\(k\).你每次要删除一条长度为\(k\)(\(k\)个点)的祖先-后代链,问你最少几次删完.现在有\(q\)个询问,每次给你一个\(k\), ...

  4. BZOJ4551[Tjoi2016&Heoi2016]树——dfs序+线段树/树链剖分+线段树

    题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均 ...

  5. HDU.5692 Snacks ( DFS序 线段树维护最大值 )

    HDU.5692 Snacks ( DFS序 线段树维护最大值 ) 题意分析 给出一颗树,节点标号为0-n,每个节点有一定权值,并且规定0号为根节点.有两种操作:操作一为询问,给出一个节点x,求从0号 ...

  6. POJ.3321 Apple Tree ( DFS序 线段树 单点更新 区间求和)

    POJ.3321 Apple Tree ( DFS序 线段树 单点更新 区间求和) 题意分析 卡卡屋前有一株苹果树,每年秋天,树上长了许多苹果.卡卡很喜欢苹果.树上有N个节点,卡卡给他们编号1到N,根 ...

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

    Danil decided to earn some money, so he had found a part-time job. The interview have went well, so ...

  8. 洛谷P3178 [HAOI2015]树上操作(dfs序+线段树)

    P3178 [HAOI2015]树上操作 题目链接:https://www.luogu.org/problemnew/show/P3178 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边 ...

  9. 【cf343】D. Water Tree(dfs序+线段树)

    传送门 题意: 给出一个以\(1\)为根的有根树,起始每个结点都为\(0\),现在有三种操作: 1.将\(v\)及\(v\)的子树都置为\(1\): 2.将\(v\)及其所有的祖先都置为\(0\): ...

  10. Educational Codeforces Round 6 E dfs序+线段树

    题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili ...

随机推荐

  1. Shell命令之文本操作

    前言 在Linux中,文本处理操作是最常见的,应用非常广泛,如果能熟练掌握,可以大大提高开发效率. awk/sed/grep是文本操作领域的“三剑客”,学会了这3个命令就可以应对绝大多数文本处理场景. ...

  2. K8s之spinnaker

    一.spinnaker概述 1.spinnaker是netflix开源的一款云发布CI/CD,其前身是Asgard,spinnaker支持各种部署目标,包括OpenStack.DC/OS.Kubern ...

  3. Code Chef April Cook-Off 2019题解

    传送门 \(PEWDSVTS\) 我哪根筋不对了要把所有可行的拿出来\(sort\)一下--还有忘开\(long\ long\)真的好难受-- int main(){ // freopen(" ...

  4. 聚合和分组F,Q和事物,cookie,session

    聚合 aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典. 键的名称是聚合值的标识符,值是计算出来的聚合值.键的名称是按照字段和聚合函数的名称自动生成出 ...

  5. Storm入门示例

    开发Storm的第一步就是设计Topology,为了方便开发者入门,首先我们设计一个简答的例子,该例子的主要的功能就是把每个单词的后面加上Hello,World后缀,然后再打印输出,整个例子的Topo ...

  6. 在vue里面使用iVew框架

    iVew框架的文档   https://www.iviewui.com/docs/guide/install 这里使用的是 npm 来安装,在项目下执行下面命令npm install iview -- ...

  7. 【转】通过js获取系统版本以及浏览器版本

    function getOsInfo() { var userAgent = navigator.userAgent.toLowerCase(); var name = 'Unknown'; var ...

  8. Android_EditText 密码框默认是小圆点 怎么改成其它的(*)?

    text.setTransformationMethod(new AsteriskPasswordTransformationMethod()); public class AsteriskPassw ...

  9. 开发工具 -- Eclipse快捷键

    [ALT+/]此快捷键为用户编辑的好帮手,能为用户提供内容的辅助,不要为记不全方法和属性名称犯愁,当记不全类.方法和属性的名字时,多体验一下[ALT+/]快捷键带来的好处吧.   [Ctrl+O]显示 ...

  10. [Java初探07]__关于面向对象的简单认识

    前言 类和对象,在我们学习Java语言的过程中,它们无时无刻不存在着,在我们还远未详细弄明白它们的意义之前,在我们不知不觉的下意识里,我们都会直接或间接的用到它们,这是因为Java是一门面向对象的语言 ...