解题思路:
其实线段树套线段树就可做,所以叫二逼平衡树。
不过还没写过线段树套Splay,所以练一下也是好的。
首先我们把平衡树中相同的值放在一个节点里,记个cnt,方便操作。
操作1:只用去线段树上logn颗平衡树上找比k小的个数即可,最后记得加一。
操作2:二分答案,再用操作一去检验,这就是线段树套Splay二逼之处,要O(log3n) ,要是线段树套线段树就不用二分答案了。
操作3:去线段树上logn颗平衡树删除一个值为k的节点,再插入y即可。如果该节点cnt>1就只用把它旋到根节点,cnt和size减一;但cnt=1时必须删除,不然会影响找前后缀的操作(亲身经历)。
操作4:去线段树上logn颗平衡树找k的前缀,最后取max即可。
操作5:去线段树上logn颗平衡树找k的后缀,最后取min即可。
除了操作2,其余操作一次都是O(log2n)的。
详见代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
if(c=='-')f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=50005,M=2000005,INF=1e8;
int n,m,ans,a[N];
int tot,rt[N<<2],son[M][2],val[M],fa[M],cnt[M],size[M];
int which(int x)
{
return son[fa[x]][1]==x;
}
void Rotate(int k,int x)
{
int y=fa[x],z=fa[y],t=which(x);
if(y==rt[k])rt[k]=x;
else son[z][which(y)]=x;
fa[y]=x,fa[x]=z;
son[y][t]=son[x][t^1],son[x][t^1]=y;
if(son[y][t])fa[son[y][t]]=y;
size[x]=size[y],size[y]=size[son[y][0]]+size[son[y][1]]+cnt[y];
}
void Splay(int k,int x,int f)
{
while(fa[x]!=f)
{
if(fa[fa[x]]!=f)
which(x)==which(fa[x])?Rotate(k,fa[x]):Rotate(k,x);
Rotate(k,x);
}
}
void Insert(int &u,int num,int f)
{
if(!u)
{
u=++tot;
val[u]=num,fa[u]=f,size[u]=1,cnt[u]=1;
return;
}
if(num==val[u])cnt[u]++;
else if(num<val[u])Insert(son[u][0],num,u);
else Insert(son[u][1],num,u);
size[u]=size[son[u][0]]+size[son[u][1]]+cnt[u];
}
void Delete(int k,int u,int num)
{
while(val[u]!=num)
if(num<val[u])u=son[u][0];
else u=son[u][1];
Splay(k,u,0);
cnt[u]--,size[u]--;
if(!cnt[u])
{
if(!son[u][1])
{
rt[k]=son[u][0],fa[son[u][0]]=0;
return;
}
int v=son[u][1];
while(son[v][0])v=son[v][0];
Splay(k,v,u);
rt[k]=v,fa[v]=0;
son[v][0]=son[u][0],fa[son[u][0]]=v;
size[v]=size[son[v][0]]+size[son[v][1]]+cnt[v];
}
}
void build(int k,int l,int r,int p,int num)
{
Insert(rt[k],num,0);
if(l==r)return;
int mid=l+r>>1;
if(p<=mid)build(k<<1,l,mid,p,num);
else build(k<<1|1,mid+1,r,p,num);
}
void get_rank(int u,int num)
{
if(!u)return;
if(num==val[u]){ans+=size[son[u][0]];return;}
if(num<val[u])get_rank(son[u][0],num);
else ans+=size[son[u][0]]+cnt[u],get_rank(son[u][1],num);
}
void query_rank(int k,int l,int r,int x,int y,int num)
{
if(x==l&&y==r)
{
get_rank(rt[k],num);
return;
}
int mid=l+r>>1;
if(y<=mid)query_rank(k<<1,l,mid,x,y,num);
else if(x>mid)query_rank(k<<1|1,mid+1,r,x,y,num);
else
{
query_rank(k<<1,l,mid,x,mid,num);
query_rank(k<<1|1,mid+1,r,mid+1,y,num);
}
}
void find(int x,int y,int num)
{
int l=0,r=INF,res;
while(l<=r)
{
int mid=l+r>>1;
ans=1;query_rank(1,1,n,x,y,mid);
if(ans<=num)l=mid+1,res=mid;
else r=mid-1;
}
cout<<res<<'\n';
}
void modify(int k,int l,int r,int p,int v)
{
Delete(k,rt[k],a[p]);
Insert(rt[k],v,0);
if(l==r)return;
int mid=l+r>>1;
if(p<=mid)modify(k<<1,l,mid,p,v);
else modify(k<<1|1,mid+1,r,p,v);
}
void get_pre(int u,int num)
{
if(!u)return;
if(val[u]<num)
{
ans=max(ans,val[u]);
get_pre(son[u][1],num);
}
else get_pre(son[u][0],num);
}
void get_suf(int u,int num)
{
if(!u)return;
if(val[u]>num)
{
ans=min(ans,val[u]);
get_suf(son[u][0],num);
}
else get_suf(son[u][1],num);
}
void find_pre(int k,int l,int r,int x,int y,int num)
{
if(x==l&&y==r)
{
get_pre(rt[k],num);
return;
}
int mid=l+r>>1;
if(y<=mid)find_pre(k<<1,l,mid,x,y,num);
else if(x>mid)find_pre(k<<1|1,mid+1,r,x,y,num);
else
{
find_pre(k<<1,l,mid,x,mid,num);
find_pre(k<<1|1,mid+1,r,mid+1,y,num);
}
}
void find_suf(int k,int l,int r,int x,int y,int num)
{
if(x==l&&y==r)
{
get_suf(rt[k],num);
return;
}
int mid=l+r>>1;
if(y<=mid)find_suf(k<<1,l,mid,x,y,num);
else if(x>mid)find_suf(k<<1|1,mid+1,r,x,y,num);
else
{
find_suf(k<<1,l,mid,x,mid,num);
find_suf(k<<1|1,mid+1,r,mid+1,y,num);
}
}
int main()
{
//freopen("lx.in","r",stdin);
//freopen("lx.out","w",stdout);
n=getint(),m=getint();
for(int i=1;i<=n;i++)
a[i]=getint(),build(1,1,n,i,a[i]);
int op,x,y,num;
for(int i=1;i<=m;i++)
{
op=getint(),x=getint(),y=getint();
if(op==1)
{
num=getint(),ans=1;
query_rank(1,1,n,x,y,num);
cout<<ans<<'\n';
continue;
}
if(op==2)
{
num=getint();
find(x,y,num);
continue;
}
if(op==3)
{
modify(1,1,n,x,y);a[x]=y;
continue;
}
if(op==4)
{
num=getint(),ans=0;
find_pre(1,1,n,x,y,num);
cout<<ans<<'\n';
continue;
}
if(op==5)
{
num=getint(),ans=INF;
find_suf(1,1,n,x,y,num);
cout<<ans<<'\n';
continue;
}
}
return 0;
}