注意:dfs序不是欧拉序
三个操作:
1. 将u及其子树全部灌水,子树就是dfs序in[u]和out[u]中间那一部分
2. 将u及其祖先排水,暴力搞tle了,一点小优化仍然tle,其实只需要将u单点排水即可,因为询问u时,如果u或u的子树的某个节点是空的,那么u一定也应该是排水的(只是没有将它排水,排水的话就超时了)。
3. 询问u时,检查u及u的子树是否全部灌水了。
但,由于操作2,比如样例中的那棵树,
先1号节点灌水,3号节点排水,把2号节点灌水,此时就会出现1号节点本来应该是排水的了,但它及它的子树却全部灌水了。
所以操作1应加一步,判断这个区间是否是灌水状态,如果是排水,那么把u的fa排水。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <stack>
#include <vector>
#include <cstring>
#include <queue>
#define msc(X) memset(X,-1,sizeof(X))
#define ms(X) memset(X,0,sizeof(X))
typedef long long LL;
using namespace std;
const int MAXN=5e5+9;
struct _Edge
{
int to,next;
}edge[MAXN<<1];
int hd[MAXN],tot,id;
int fa[MAXN],in[MAXN],out[MAXN];
void addedge(int u,int v)
{
edge[tot].to=v;edge[tot].next=hd[u];hd[u]=tot++;
}
void dfs(int u,int pre)
{
fa[u]=pre;
in[u]=id++;
for(int i=hd[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(v!=pre) dfs(v,u);
}
out[u]=id++;
}
int tree[MAXN<<3],lazy[MAXN<<3];//dfs序本身就是2倍
void push_down(int tn,int l,int r)
{
if(lazy[tn]!=-1){
lazy[tn<<1]=lazy[tn<<1|1]=lazy[tn];
tree[tn<<1]=tree[tn<<1|1]=lazy[tn];
lazy[tn]=-1;
}
}
void change(int tn,int l,int r,int x,int y,int op)
{
if(x<=l&&r<=y) {tree[tn]=op;lazy[tn]=op;return;}
push_down(tn,l,r);
int mid=(l+r)>>1;
if(x<=mid) change(tn<<1,l,mid,x,y,op);
if(y>mid) change(tn<<1|1,mid+1,r,x,y,op);
tree[tn]=min(tree[tn<<1],tree[tn<<1|1]);
}
bool query(int tn,int l,int r,int x,int y)
{
if(x<=l&&r<=y) return tree[tn];
push_down(tn,l,r);
int mid=(l+r)>>1;
if(y<=mid) return query(tn<<1,l,mid,x,y);
else if(x>mid) return query(tn<<1|1,mid+1,r,x,y);
else return query(tn<<1,l,mid,x,mid)&&query(tn<<1|1,mid+1,r,mid+1,y);
}
int main(int argc, char const *argv[])
{
int n,q;
msc(hd);
tot=id=0;
scanf("%d",&n);
while(--n){
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dfs(1,0);
ms(tree);
msc(lazy);
scanf("%d",&q);
while(q--){
int op,v;
scanf("%d%d",&op,&v);
if(op==3) printf("%d\n",query(1,0,id-1,in[v],out[v]) );
else if(op==1) {
bool tmp=query(1,0,id-1,in[v],out[v]);
change(1,0,id-1,in[v],out[v],1);
if(fa[v]&&!tmp) change(1,0,id-1,in[fa[v]],in[fa[v]],0);
}
else change(1,0,id-1,in[v],in[v],0);//单点更新
}
return 0;
}