并不对劲的loj6498. 「雅礼集训 2018 Day2」农民
题目大意
有一棵\(n\)个点有点权\(w\)(可能有重复)的二叉树。\(m\)次操作,操作种类如下:
1.给出点\(x\),修改\(x\)的权值;
2.给出点\(x\),交换它和它的子树内所有点的左右儿子;
3.给出点\(x\),问从根出发是否可以用“当前点点权小于\(w_x\)就往右走,大于\(w_x\)就往左走,等于\(w_x\)就停”来走到点\(x\)。
\(n,m\leq 10^5;\)
题解
当且仅当根到\(x\)路径上所有点满足“\(x\)在这个点左子树时点权大于\(w_x\),在右子树时点权小于\(x\)”时操作3的答案是“是”。
相当于前一类点的最小值大于\(x\),后一类点的最大值大于\(x\)。可以用两棵线段树维护。
操作2相当于两个线段树上的一些点。
代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 100007
#define maxm 200007
#define ls ch[u][0]
#define rs ch[u][1]
#define mi ((l+r)>>1)
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
if(x==0){putchar('0'),putchar('\n');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
return;
}
int n,m,a[maxn],son[maxn][2],wson[maxn],fa[maxn],siz[maxn],cntnd;
int dfn[maxn],tim,top[maxn],tr[maxn],dep[maxn],mn[maxn<<3],mx[maxn<<3],ch[maxn<<3][2],rtmx,rtmn;
int inf[2]={(int)(1e9+1),(int)(-1e9-1)};
int lt(int x){return x&(-x);}
void add(int x,int k){for(;x<=n;x+=lt(x))tr[x]^=k;return;}
int ask(int x){int k=0;for(;x;x-=lt(x))k^=tr[x];return k;}
void pu(int u)
{
mx[u]=max(mx[ls],mx[rs]);
mn[u]=min(mn[ls],mn[rs]);
return;
}
int build(int l,int r)
{
int u=++cntnd;
if(l==r){mn[u]=inf[0],mx[u]=inf[1];return u;}
ls=build(l,mi),rs=build(mi+1,r);pu(u);return u;
}
void adda(int u,int l,int r,int x,int k)
{
if(l==r){mn[u]=mx[u]=k;return;}
if(x<=mi)adda(ls,l,mi,x,k);
else adda(rs,mi+1,r,x,k);
pu(u);return;
}
void chg(int & ua,int & ub,int l,int r,int x,int y)
{
if(x<=l&&r<=y){swap(ua,ub);return;}
if(x<=mi)chg(ch[ua][0],ch[ub][0],l,mi,x,y);
if(y>mi)chg(ch[ua][1],ch[ub][1],mi+1,r,x,y);
pu(ua),pu(ub);return;
}
int aska(int u,int l,int r,int x,int y,int typ)//typ=0:mn
{
if(x<=l&&r<=y){return typ?mx[u]:mn[u];}
int res=inf[typ];
if(x<=mi)res=aska(ls,l,mi,x,y,typ);
if(y>mi)res=typ?max(res,aska(rs,mi+1,r,x,y,typ)):min(res,aska(rs,mi+1,r,x,y,typ));
return res;
}
void getson(int u)
{
siz[u]=1;
rep(i,0,1)if(son[u][i])
{
dep[son[u][i]]=dep[u]+1,fa[son[u][i]]=u,getson(son[u][i]),siz[u]+=siz[son[u][i]];
if(!wson[u]||siz[wson[u]]<siz[son[u][i]])wson[u]=son[u][i];
}
}
void gettop(int u,int anc)
{
dfn[u]=++tim,top[u]=anc;
if(wson[u])gettop(wson[u],anc);
rep(i,0,1)if(son[u][i]&&son[u][i]!=wson[u])gettop(son[u][i],son[u][i]);
}
void gettr(int u)
{
rep(i,0,1)if(son[u][i])
{
if(i)adda(rtmx,1,n,dfn[son[u][i]],a[u]);
else adda(rtmn,1,n,dfn[son[u][i]],a[u]);
gettr(son[u][i]);
}
}
int getnum(int x,int typ)
{
int res=inf[typ];
while(x)
{
int tmp=aska(typ?rtmx:rtmn,1,n,dfn[top[x]],dfn[x],typ);
res=typ?max(res,tmp):min(res,tmp),x=fa[top[x]];
}
return res;
}
int main()
{
n=read(),m=read();
rep(i,1,n)a[i]=read(),son[i][0]=read(),son[i][1]=read();
rtmx=build(1,n),rtmn=build(1,n);getson(1),gettop(1,1),gettr(1);
while(m--)
{
int f=read(),x=read();
if(f==1)
{
int y=read();a[x]=y;
rep(i,0,1)if(son[x][i])
{
int px=ask(dfn[son[x][i]]);
if(i^px){adda(rtmx,1,n,dfn[son[x][i]],a[x]);}
else {adda(rtmn,1,n,dfn[son[x][i]],a[x]);}
}
}
else if(f==2)
{
chg(rtmn,rtmx,1,n,dfn[x]+1,dfn[x]+siz[x]-1),add(dfn[x]+1,1),add(dfn[x]+siz[x],1);
}
else
{
int mxl=getnum(x,1),mnr=getnum(x,0);
if(mxl<a[x]&&mnr>a[x])puts("YES");
else puts("NO");
}
}
return 0;
}
一些感想
为啥我打不过人???