Water Tree
题意:有n个点的树,1为根,然后有三种操作
(1)将节点u及其子树的所有节点变为1
(2)将节点u变为0
(3)查询节点u及其子树的所有节点是否为1
分析:首先可以将树形结构变为线性结构,即用DFS序将节点u及其控制的子树节点变成区间[ in[u] , out[u] ],然后对于(2)操作,就是线段树的单点修改;对于(1)操作,由于当节点u原来为0,其所有的祖先节点都为0,那么我们可以先将其父节点单点修改为0(相当于将其所有祖先节点改为0),然后再将u节点及其子树节点改为1,这个操作就是区间更新;对于(3)操作,我们其实就是查询节点u所控制的区间是否全部为1,那么就是区间查。这个过程用&运算来来保存节点的信息。
代码:
#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<vector>
#include<math.h>
#include<map>
#include<queue>
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
typedef pair<int,int> pii;
const int maxn = 5e5 + 10;
int n;
int dfn[maxn],in[maxn],out[maxn];
int fa[maxn];
int idx;
struct Edge{
int to,nex;
}edge[maxn*2];
int tot,head[maxn];
void addedge(int u,int v){
edge[tot]=Edge{v,head[u]};
head[u]=tot++;
}
void init(){
tot=idx=0;
memset (head,-1,sizeof (head));
}
void dfs(int u,int pre){//求dfs序和fa数组
dfn[u]=++idx;
fa[u]=pre;
in[u]=idx;
for (int i=head[u];i!=-1;i=edge[i].nex){
int v=edge[i].to;
if (v==pre)continue;
dfs(v,u);
}
out[u]=idx;
}
int tree[maxn*4];
int setv[maxn*4];//lazy标记
void push_down(int rt){
if (setv[rt]==1){
setv[rt*2]=setv[rt*2+1]=setv[rt];
tree[rt*2]=tree[rt*2+1]=setv[rt];
setv[rt]=-1;
}
}
void update (int rt,int l,int r,int L,int R,int val){//区间更新
if (l>=L&&r<=R){
setv[rt]=val;
tree[rt]=val;
return ;
}
push_down(rt);
int mid=(l+r)/2;
if (L<=mid)update(rt*2,l,mid,L,R,val);
if (R>mid)update(rt*2+1,mid+1,r,L,R,val);
tree[rt]=tree[rt*2]&&tree[rt*2+1];
}
void update (int rt,int l,int r,int pos){//单点修改
if (l==r){
tree[rt]=0;
return;
}
push_down(rt);
int mid=(l+r)/2;
if (pos<=mid)update(rt*2,l,mid,pos);
else update(rt*2+1,mid+1,r,pos);
tree[rt]=tree[rt*2]&&tree[rt*2+1];
}
int query(int rt,int l,int r,int L,int R){//区间查询
if (l>=L&&R>=r){
return tree[rt];
}
push_down(rt);
int mid=(l+r)/2;
int ans=1000000;
if (L<=mid){
ans = min(query(rt*2,l,mid,L,R),ans);
}
if (R>mid)ans = min(query(rt*2+1,mid+1,r,L,R),ans);
return ans;
}
int main ()
{
while(scanf ("%d",&n)!=EOF){
init();
memset (tree,0,sizeof (tree));
memset (setv,-1,sizeof (setv));
int u,v;
for (int i=0;i<n-1;i++){
scanf ("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dfs(1,-1);
int q,op;
scanf ("%d",&q);
while (q--){
scanf ("%d%d",&op,&u);
if (op==1){
if (!query(1,1,idx,in[u],out[u])&&fa[u]!=-1){//如果该节点的父节点为为0,则修改
update(1,1,idx,in[fa[u]]);
}
update(1,1,idx,in[u],out[u],1);
}else if (op==2){
update(1,1,idx,in[u]);
}else {
int ans = query(1,1,idx,in[u],out[u]);
printf ("%d\n",ans);
}
}
}
return 0;
}
/*
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
*/