联考20200522 T2 「雅礼集训 2018 Day2」农民

题目传送门

分析:
一些肥料((l,r))流过一个点,被分成了两部分流向两边((l,a[i]),(a[i],r)),所有肥料只这个点的分流区间为((-INF,a[i]),(a[i],INF))
流到一个点的肥料区间为它的祖先分流区间的交集
交集求并满足交换律
考虑树链剖分维护一段重链的区间交集
设结构体((l1,r1,l2,r2)),其中((l1,r1))为该点重边的区间,((l2,r2))为轻边的区间(这是个二叉树,一条重边一条轻边)
翻转时可以直接交换((l1,r1))((l2,r2)),轻重儿子关键值只有这两个,无需改变树的结构
不难发现交集也可以直接交换,我们便可以使用线段树的区间翻转了
每次合并重链,暴力合并路径上轻边((logn)级别),可以接受
复杂度(O(nlog^{2}n))

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<iostream>
#include<map>
#include<string>

#define maxn 200005
#define INF 0x3f3f3f3f

using namespace std;

inline long long getint()
{
	long long num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n,m,rt,fa[maxn],cur;
int a[maxn],ch[maxn][2];
int pos[maxn],id[maxn],tp[maxn],sz[maxn],son[maxn];
struct node{
	int l1,r1,l2,r2;
	node rev(){return (node){l2,r2,l1,r1};}
	friend node operator +(node x,node y){return (node){max(x.l1,y.l1),min(x.r1,y.r1),max(x.l2,y.l2),min(x.r2,y.r2)};}
}t[maxn<<2];
int rev[maxn<<2];

inline void dfs1(int u)
{
	sz[u]=1;
	for(int i=0,v;i<2;i++)if(v=ch[u][i])
		dfs1(ch[u][i]),sz[u]+=sz[ch[u][i]];
	son[u]=sz[ch[u][0]]<sz[ch[u][1]]?1:0;
}

inline void dfs2(int u,int ac)
{
	pos[u]=++cur,id[cur]=u,tp[u]=ac;
	if(ch[u][son[u]])dfs2(ch[u][son[u]],ac);
	if(ch[u][son[u]^1])dfs2(ch[u][son[u]^1],ch[u][son[u]^1]);
}

inline void build(int i,int l,int r)
{
	if(l==r)
	{
		int u=id[l];
		t[i]=son[u]?(node){a[u],INF,-INF,a[u]}:(node){-INF,a[u],a[u],INF};
		return;
	}
	int mid=(l+r)>>1;build(i<<1,l,mid),build(i<<1|1,mid+1,r);
	t[i]=t[i<<1]+t[i<<1|1];
}

inline void pushdown(int i)
{
	if(rev[i])
	{
		rev[i<<1]^=1,t[i<<1]=t[i<<1].rev();
		rev[i<<1|1]^=1,t[i<<1|1]=t[i<<1|1].rev();
		rev[i]^=1;
	}
}

inline void update(int i,int l,int r,int p)
{
	if(l==r)
	{
		int u=id[l];
		t[i]=son[u]^rev[i]?(node){a[u],INF,-INF,a[u]}:(node){-INF,a[u],a[u],INF};
		return;
	}
	pushdown(i);
	int mid=(l+r)>>1;
	if(p<=mid)update(i<<1,l,mid,p);
	else update(i<<1|1,mid+1,r,p);
	t[i]=t[i<<1]+t[i<<1|1];
}

inline void modify(int i,int l,int r,int ql,int qr)
{
	if(r<ql||qr<l)return;
	if(ql<=l&&r<=qr){t[i]=t[i].rev(),rev[i]^=1;return;}
	pushdown(i);
	int mid=(l+r)>>1;
	modify(i<<1,l,mid,ql,qr),modify(i<<1|1,mid+1,r,ql,qr);
	t[i]=t[i<<1]+t[i<<1|1];
}

inline node query(int i,int l,int r,int ql,int qr)
{
	if(ql<=l&&r<=qr)return t[i];
	pushdown(i);
	int mid=(l+r)>>1;node tmp=(node){-INF,INF,-INF,INF};
	if(ql<=mid)tmp=tmp+query(i<<1,l,mid,ql,qr);
	if(qr>mid)tmp=tmp+query(i<<1|1,mid+1,r,ql,qr);
	return tmp;
}

inline int query(int u,int num)
{
	node tmp=(node){-INF,INF,-INF,INF};
	while(u)
	{
		if(u!=tp[u])tmp=tmp+query(1,1,n,pos[tp[u]],pos[fa[u]]);
		u=fa[tp[u]];
		if(u)tmp=tmp+query(1,1,n,pos[u],pos[u]).rev();
	}
	return tmp.l1<num&&num<tmp.r1;
}

int main()
{
	n=getint(),m=getint();
	for(int i=1;i<=n;i++)a[i]=getint(),fa[ch[i][0]=getint()]=i,fa[ch[i][1]=getint()]=i;
	for(int i=1;i<=n;i++)if(!fa[i])rt=i;
	dfs1(rt),dfs2(rt,rt),build(1,1,n);
	while(m--)
	{
		int op=getint(),u=getint();
		if(op==1)a[u]=getint(),update(1,1,n,pos[u]);
		if(op==2)modify(1,1,n,pos[u],pos[u]+sz[u]-1);
		if(op==3)puts(query(u,a[u])?"YES":"NO");
	}
}

联考20200522 T2 「雅礼集训 2018 Day2」农民