LOJ6498「雅礼集训 2018 Day2」农民

https://loj.ac/p/6498

考虑什么时候节点 (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;
}
原文地址:https://www.cnblogs.com/suxxsfe/p/15398732.html