D. Water Tree
The vertices of the tree are numbered from 1 1 1 to n with the root at vertex 1 1 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:
- Fill vertex v v v with water. Then v and all its children are filled with water.
- Empty vertex v v v. Then v v v and all its ancestors are emptied.
- Determine whether vertex v v 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 ) n\ (1 ≤ n ≤ 500000) n (1 ≤ n ≤ 500000) — the number of vertices in the tree. Each of the following n − 1 n - 1 n − 1 lines contains two space-separated numbers a i , b i ( 1 ≤ a i , b i ≤ n , a i ! = b i ) a_i, b_i (1 ≤ a_i, b_i ≤ n, a_i != b_i) ai,bi(1 ≤ ai, bi ≤ n,ai != bi) — the edges of the tree.
The next line contains a number q ( 1 ≤ q ≤ 500000 ) q (1 ≤ q ≤ 500000) q(1 ≤ q ≤ 500000) — the number of operations to perform. Each of the following q lines contains two space-separated numbers c i ( 1 ≤ c i ≤ 3 ) , v i ( 1 ≤ v i ≤ n ) c_i (1 ≤ c_i ≤ 3), v_i (1 ≤ v_i ≤ n) ci(1 ≤ ci ≤ 3),vi(1 ≤ vi ≤ n), where c i c_i ci is the operation type (according to the numbering given in the statement), and v i v_i 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 3 3 operation print 1 1 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
-
题意
就是给你一颗根节点为1的树,开始所有节点权值为0,需要支持的操作有:- 将以 v v v为根节点的子树的所有节点的权值更新为 1 1 1
- 将从 1 1 1到 v v v的最短路径上的所有点的权值更新为 0 0 0
- 查询节点 v v v的权值
-
做法
-
没想到 d i v 1 div1 div1也会出模板题2333
-
首先你可能会想着用一个dfs序加一个树状数组或者线段树维护一下子树的修改,但是链呢?自然的想到树链剖分,刚好剖出来的子树编号也是连续的,然后这题实际上是在考你线段树而不是树链剖分,线段树维护的时候也许你会打两个标记(但是这样好像并不行?因为两个标记的话同一个节电可能存在两个标记,那么你先 d o w n down down哪一个呢?)所以考虑一个 m a r k mark mark,其含义如下:
- − 1 -1 −1:该区间没有操作
- 0 0 0:该区间全部清零
- 1 1 1:该区间全部变成1
然后再用一个 v a l val val记录当前区间的值是否单一,因为如果都是一样的话你就不用继续 D F S DFS DFS了,直接返回当前区间的值就行了, v a l val val含义如下:
- − 1 -1 −1:该区间既有 0 0 0又有 1 1 1
- 0 0 0:该区间全部都为 0 0 0
- 1 1 1:该区间全部都为 1 1 1
-
-
附代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+10;
vector<int> vec[maxn];
int n,q,u,v,opt;
int h[maxn],fa[maxn],top[maxn],id[maxn],son[maxn],siz[maxn],rk[maxn],tot;
struct node{
int l,r,val,mark; //val:-1:混合 0:没有水 1:有水
}tree[maxn<<2]; //mark:-1无操作 0:清0 1:区间全部加水
struct segment_tree{
void build(int le,int ri,int id){
tree[id].l=le,tree[id].r=ri,tree[id].val=0,tree[id].mark=-1;
if(le==ri) return;
int mid=(le+ri)>>1;
build(le,mid,id<<1);
build(mid+1,ri,id<<1|1);
pushup(id);
}
void pushup(int id){
if(tree[id<<1].val==tree[id<<1|1].val) tree[id].val=tree[id<<1].val;
else tree[id].val=-1;
}
void down(int id){
tree[id<<1].mark=tree[id<<1|1].mark=tree[id].mark;
tree[id<<1].val=tree[id<<1|1].val=tree[id].mark;
tree[id].mark=-1;
}
int len(int id){
return tree[id].r-tree[id].l+1;
}
void update(int l,int r,int id,int opt){
if(l<=tree[id].l&&r>=tree[id].r){
tree[id].mark=opt;
if(opt) tree[id].val=1;
else tree[id].val=0;
return;
}
if(tree[id].mark!=-1) down(id);
int mid=(tree[id].l+tree[id].r)>>1;
if(l<=mid) update(l,r,id<<1,opt);
if(r>mid) update(l,r,id<<1|1,opt);
pushup(id);
}
int query(int k,int id){
int ans=-1;
if(tree[id].l==tree[id].r) return tree[id].val;
if(tree[id].val!=-1) return tree[id].val;
if(tree[id].mark!=-1) down(id);
int mid=(tree[id].l+tree[id].r)>>1;
if(k<=mid) ans=query(k,id<<1);
else ans=query(k,id<<1|1);
pushup(id);
return ans;
}
}dat;
struct tree{
tree(){
tot=0;
memset(son,0,sizeof(son));
memset(h,0,sizeof(h));
}
void build(){
dfs1(1,0,1);dfs2(1,1);
dat.build(1,n,1);
}
void dfs1(int cur,int fath,int he){ //dfs(root,0,1)
h[cur]=he;fa[cur]=fath;siz[cur]=1;
for(int i=0;i<vec[cur].size();i++){
if(vec[cur][i]!=fath){
dfs1(vec[cur][i],cur,he+1);
siz[cur]+=siz[vec[cur][i]];
if(siz[vec[cur][i]]>siz[son[cur]]) son[cur]=vec[cur][i];
}
}
}
void dfs2(int cur,int topp){ //dfs2(root,root)
id[cur]=++tot;rk[tot]=cur;top[cur]=topp;
if(son[cur]) dfs2(son[cur],topp);
for(int i=0;i<vec[cur].size();i++){
if(vec[cur][i]!=fa[cur]&&vec[cur][i]!=son[cur]){
dfs2(vec[cur][i],vec[cur][i]);
}
}
}
int query(int x){
return dat.query(id[x],1);
}
void update(int x,int y){
int topx=top[x],topy=top[y];
while(topx!=topy){
if(h[topx]>=h[topy]){
dat.update(id[topx],id[x],1,0);
x=fa[topx],topx=top[x];
}else{
dat.update(id[topy],id[y],1,0);
y=fa[topy],topy=top[y];
}
}
dat.update(min(id[x],id[y]),max(id[x],id[y]),1,0);
}
void update_son_tree(int x){
dat.update(id[x],id[x]+siz[x]-1,1,1);
}
}chain;
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++){
scanf("%d %d",&u,&v);
vec[u].push_back(v);
vec[v].push_back(u);
}
chain.build();
scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%d %d",&opt,&u);
if(opt==1){
chain.update_son_tree(u);
}else if(opt==2){
chain.update(1,u);
}else printf("%d\n",chain.query(u));
}
}