其实是树剖QwQ不过个人感觉和线段树还是很像的…所以树剖的本质大约就是dfs序+线段树?
in[]记录节点的节点的dfs编号
out[]记录节点的控制范围
(in[i]<=in[j]<=out[i]当且仅当j节点属于以i为根节点的子树)
pos[i]记录i节点的父亲节点
这样就能用[1,n]表示一颗以1为根节点的树了
1、每次要给i节点加水的时候就把[in[i],out[i]]的值修改为1,用lazy标记的方式很容易做到
**如果给i节点加水的时候发现有子节点是空的,那么说明i节点的父亲节点一定是空的【否则作为i节点的父亲节点,如果它有水它的子节点一定都是有水的】,如此递推,可以很容易发现此时从i节点父亲向上的祖先全部都是空的,这样就可以把加水后的问题转化为将i的父亲节点清空,父亲节点的查找在dfs时已经提前记录,新问题也就很容易转化为问题2
2、由根向下找到将要清空的点i(即区间[in[i],in[i]]),每一步都pushdown一次,将该点的值修改为0,然后在回溯时每一步都重置节点【如果子节点有空节点,父节点必然是空节点】
3、查询点i状态(区间[in[i],in[i]]),记得每一步都pushdown即可
#include<iostream>
#include<vector>
#include<stdio.h>
#include<windows.h>
#define lson (o<<1)
#define rson ((o<<1)|1)
using namespace std;
const int maxn=500005;
vector<int> edge[maxn];
int n,q,a[maxn],b[maxn],in[maxn],out[maxn],pos[maxn],c,v,tot;
bool lazy[maxn*4],tree[maxn*4],ans;
void dfs(int x,int pre)
{
in[x]=++tot;
for(int i=0;i<edge[x].size();i++)
if(edge[x][i]!=pre)
pos[edge[x][i]]=x,dfs(edge[x][i],x);
out[x]=tot;
}
void pushdown(int o,int l,int r)
{
if(lazy[o])
if(l==r)tree[o]=1;
else tree[o]=tree[lson]=tree[rson]=lazy[lson]=lazy[rson]=1;
lazy[o]=0;
}
void maintain(int o,int l,int r)
{
if(l!=r)tree[o]=tree[lson] && tree[rson];
}
void fillwater(int o,int l,int r)
{
pushdown(o,l,r);
if(l>=in[v] && r<=out[v])
{
//cout<<in[v]<<' '<<out[v]<<' '<<o<<' '<<l<<' '<<r<<endl;
ans&=tree[o];
lazy[o]=1;
pushdown(o,l,r);
return;
}
if(l>out[v] || r<in[v])return;
int mid=(l+r)/2;
fillwater(lson,l,mid);
fillwater(rson,mid+1,r);
maintain(o,l,r);
}
void emptywater(int o,int l,int r)
{
pushdown(o,l,r);
if(l>in[v] || r<in[v])return;
if(l==r)
{
//cout<<in[v]<<' '<<out[v]<<' '<<o<<' '<<l<<' '<<r<<endl;
pushdown(o,l,r);
tree[o]=0;
return;
}
int mid=(l+r)/2;
emptywater(lson,l,mid);
emptywater(rson,mid+1,r);
maintain(o,l,r);
}
void query(int o,int l,int r)
{
//cout<<tree[o]<<' '<<o<<' '<<l<<' '<<r<<endl;
pushdown(o,l,r);
if(l>=in[v] && r<=out[v])
{
pushdown(o,l,r);
ans&=tree[o];
return;
}
if(l>out[v] || r<in[v])return;
int mid=(l+r)/2;
query(lson,l,mid);
query(rson,mid+1,r);
}
int main(void)
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d%d",&a[i],&b[i]);
edge[a[i]].push_back(b[i]);
edge[b[i]].push_back(a[i]);
}
//cout<<"dfs"<<endl;
dfs(1,0);
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
scanf("%d%d",&c,&v);
//cout<<"que"<<' '<<in[v]<<' '<<out[v]<<endl;
//Sleep(2000);
if(c==1)
{
ans=1;
fillwater(1,1,tot);
v=pos[v];
if(v && (!ans))emptywater(1,1,tot);
}
if(c==2)emptywater(1,1,tot);
if(c==3)ans=1,query(1,1,tot),printf("%d\n",(int)ans);
//cout<<c<<endl;
}
//cin>>n;
return 0;
}