题目链接
题意:给定一棵树,初始树中所有数都是0,然后有三个操作,1、将v和它的子树变1;2、将v和它的所有祖先节点变0,3、输出v的值。
思路:1和3都很容易解决,用dfs序+线段树就可以了,但2不好处理,看大佬好像都是用树剖,可惜弱鸡不会QAQ,还有一种很妙的方法,我们对于2可以单点更新,线段树来维护区间最小值,,在1操作前将v的父亲节点设为0就行(类似于差分思想),然后查询的时候如果v和它的子树里有一个0的话答案就是0了,否则都是1。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+5;
vector<int>g[maxn];
struct node{
int l,r,w,lazy;
}tree[maxn<<2];
int cnt=0,in[maxn],out[maxn],pre[maxn];
void dfs(int u,int fa)
{
pre[u]=fa;
in[u]=++cnt;
for(int to:g[u])
{
if(to==fa) continue;
dfs(to,u);
}
out[u]=cnt;
}
void pushup(int x)
{
tree[x].w=min(tree[x<<1].w,tree[x<<1|1].w);
}
void pushdown(int x)
{
if(tree[x].lazy)
{
tree[x<<1].w=tree[x<<1].lazy=tree[x].lazy;
tree[x<<1|1].w=tree[x<<1|1].lazy=tree[x].lazy;
tree[x].lazy=0;
}
}
void build(int l,int r,int x)
{
tree[x].l=l;tree[x].r=r;
if(l==r){
tree[x].w=0;
return ;
}
int mid=(l+r)>>1;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
pushup(x);
}
void update(int x,int l,int r,int val)
{
if(l<=tree[x].l&&tree[x].r<=r)
{
tree[x].w=tree[x].lazy=val;
return ;
}
pushdown(x);
int mid=(tree[x].l+tree[x].r)>>1;
if(l<=mid) update(x<<1,l,r,val);
if(mid<r) update(x<<1|1,l,r,val);
pushup(x);
}
int query(int x,int l,int r)
{
int ans=2;
if(l<=tree[x].l&&tree[x].r<=r)
{
return tree[x].w;
}
pushdown(x);
int mid=(tree[x].l+tree[x].r)>>1;
if(l<=mid) ans=query(x<<1,l,r);
if(mid<r) ans=min(ans,query(x<<1|1,l,r));
return ans;
}
int main()
{
int n,u,v,op,m,t;
scanf("%d",&n);
for(int i=1;i<n;++i)
{
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);
build(1,n,1);
scanf("%d",&m);
while(m--)
{
scanf("%d%d",&op,&t);
if(op==1){
int minn=query(1,in[t],out[t]);
if(minn==0&&t>1) update(1,in[pre[t]],in[pre[t]],0);
update(1,in[t],out[t],1);
}
else if(op==2) update(1,in[t],in[t],0);
else printf("%d\n",query(1,in[t],out[t])==0?0:1);
}
}