联考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");
}
}