考虑什么时候节点 (u) 是可以拿到肥料的
他往根走,走到过程中如果是作为一个右儿子走上 (fa),则有一个要求 (w_u>w_{fa}),若作为一个左儿子走上,则有一个要求 (w_u<w_{fa})
于是树剖+线段树,维护作为右儿子网上走的最大的 (maxr=w_{fa}),作为左儿子网上走的最小的 (minl=w_{fa})
由于还有翻转操作,需要类似的维护 (minr) 和 (maxl)
#define N 100006
int n,m;
int a[N];
int ls[N],rs[N],fa[N];
int size[N],son[N];
int dfscnt,dfn[N],top[N],id[N];
void dfs(int u){
if(ls[u]) fa[ls[u]]=u,dfs(ls[u]);
if(rs[u]) fa[rs[u]]=u,dfs(rs[u]);
size[u]=1+size[ls[u]]+size[rs[u]];
son[u]=size[ls[u]]>size[rs[u]]?ls[u]:rs[u];
}
void dfs2(int u,int topnow){
if(!u) return;
dfn[u]=++dfscnt;id[dfscnt]=u;top[u]=topnow;
if(son[u]==ls[u]) dfs2(ls[u],topnow),dfs2(rs[u],rs[u]);
else if(son[u]==rs[u]) dfs2(rs[u],topnow),dfs2(ls[u],ls[u]);
}
struct Node{
Node *ls,*rs;
int rev;
int maxl,maxr,minl,minr;
inline void pushdown(){
if(!rev) return;
rev=0;ls->rev^=1;rs->rev^=1;
std::swap(ls->minl,ls->minr);std::swap(ls->maxl,ls->maxr);
std::swap(rs->minl,rs->minr);std::swap(rs->maxl,rs->maxr);
}
inline void pushup(){
maxl=std::max(ls->maxl,rs->maxl);maxr=std::max(ls->maxr,rs->maxr);
minl=std::min(ls->minl,rs->minl);minr=std::min(ls->minr,rs->minr);
}
}dizhi[N*2],*root;int tot;
int isR[N];
void build(Node *&tree,int l,int r){
tree=&dizhi[++tot];
if(l==r){
tree->maxr=tree->maxl=-1;tree->minl=tree->minr=INT_INF;
if(id[l]==1);
else if(isR[id[l]]^tree->rev) tree->maxr=tree->minr=a[fa[id[l]]];
else tree->maxl=tree->minl=a[fa[id[l]]];
return;
}
int mid=(l+r)>>1;
build(tree->ls,l,mid);build(tree->rs,mid+1,r);
tree->pushup();
}
void change(Node *tree,int l,int r,int pos){
if(l==r){
tree->maxr=tree->maxl=-1;tree->minl=tree->minr=INT_INF;
if(id[l]==1);
else if(isR[id[l]]^tree->rev) tree->maxr=tree->minr=a[fa[id[l]]];
else tree->maxl=tree->minl=a[fa[id[l]]];
return;
}
tree->pushdown();
int mid=(l+r)>>1;
pos<=mid?change(tree->ls,l,mid,pos):change(tree->rs,mid+1,r,pos);
tree->pushup();
}
void rev(Node *tree,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr) return std::swap(tree->minl,tree->minr),std::swap(tree->maxl,tree->maxr),tree->rev^=1,void();
tree->pushdown();
int mid=(l+r)>>1;
if(ql<=mid) rev(tree->ls,l,mid,ql,qr);
if(qr>mid) rev(tree->rs,mid+1,r,ql,qr);
tree->pushup();
}
std::pair<int,int> check(Node *tree,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr) return std::make_pair(tree->minl,tree->maxr);
tree->pushdown();
int mid=(l+r)>>1;
if(qr<=mid) return check(tree->ls,l,mid,ql,qr);
if(ql>mid) return check(tree->rs,mid+1,r,ql,qr);
std::pair<int,int>L=check(tree->ls,l,mid,ql,qr),R=check(tree->rs,mid+1,r,ql,qr);
return std::make_pair(std::min(L.first,R.first),std::max(L.second,R.second));
}
inline int check(int u){
int minl=INT_INF,maxr=-1,w=a[u];
std::pair<int,int>now;
while(u){
now=check(root,1,n,dfn[top[u]],dfn[u]);
minl=std::min(minl,now.first);maxr=std::max(maxr,now.second);
u=fa[top[u]];
}
return w<minl&&w>maxr;
}
int main(){
// freopen("tree1.in","r",stdin);
n=read();m=read();
static int notroot[N];
for(int i=1;i<=n;i++) a[i]=read(),notroot[ls[i]=read()]=1,notroot[rs[i]=read()]=1,isR[rs[i]]=1;
int rt;
for(int i=1;i<=n;i++)if(!notroot[i]) rt=i;
dfs(rt);
dfs2(rt,rt);
build(root,1,n);
while(m--){
int op=read(),x=read();
if(op==1){
a[x]=read();
if(ls[x]) change(root,1,n,dfn[ls[x]]);
if(rs[x]) change(root,1,n,dfn[rs[x]]);
}
else if(op==2) size[x]>1?rev(root,1,n,dfn[x]+1,dfn[x]+size[x]-1):void();
else if(op==3) puts(check(x)?"YES":"NO");
}
return 0;
}