题意
我用了线段树套平衡树(Splay)去做。
分别说每一问:
第一问:求一个数区间排名:
我们求出区间内小于这个数的个数,加(1)即可。
第二问:求区间第K大:
我们显然不能在(log n)个平衡树上求这个东西,于是我们在外面二分答案(mid),之后判断其排名与(k)的关系即可。
第三问:单点修改:
我们将从(1)到叶子的每个点的平衡树都删除原数,加入新数即可。
第四/五问:求区间某个数的前驱和后继:
这两问是相同的,我们只要在(log n)个平衡树上分别求一遍,最后取(max)或(min)即可。
code:
#include<bits/stdc++.h>
using namespace std;
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
const int maxn=4*1e6+10;
const int inf=2147483647;
int n,m;
int a[maxn],root[maxn];
inline int read()
{
char c=getchar();int res=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
return res*f;
}
namespace Splay
{
int tot;
int fa[maxn],val[maxn],size[maxn],cnt[maxn];
int ch[maxn][2];
inline void clear(int x){fa[x]=size[x]=cnt[x]=val[x]=ch[x][0]=ch[x][1]=0;}
inline int get(int x){return ch[fa[x]][1]==x;}
inline void up(int x){size[x]=size[ch[x][0]]+size[ch[x][1]]+cnt[x];}
inline void rotate(int x)
{
int y=fa[x],z=fa[y],k=get(x),w=ch[x][k^1];
if(z)ch[z][get(y)]=x;ch[x][k^1]=y;ch[y][k]=w;
if(w)fa[w]=y;fa[y]=x;fa[x]=z;
up(y),up(x);
}
inline void splay(int p,int x,int goal=0)
{
while(fa[x]!=goal)
{
int y=fa[x];
if(fa[y]!=goal)rotate(get(x)==get(y)?y:x);
rotate(x);
}
if(!goal)root[p]=x;
}
inline void insert(int p,int x)
{
if(!root[p])
{
root[p]=++tot;
val[tot]=x;size[tot]=cnt[tot]=1;
return;
}
int now=root[p],last=0;
while(now&&val[now]!=x)last=now,now=ch[now][val[now]<x];
if(now)cnt[now]++;
else
{
now=++tot;
if(last)fa[now]=last,ch[last][val[last]<x]=now;
val[now]=x;size[now]=cnt[now]=1;
}
splay(p,now);
}
inline int getrk(int p,int x)
{
int now=root[p],res=0;
while(now)
{
if(val[now]>x)now=ch[now][0];
else if(val[now]<x)res+=size[ch[now][0]]+cnt[now],now=ch[now][1];
else {res+=size[ch[now][0]];break;}
}
return res;
}
inline int find(int p,int k)
{
int now=root[p];
while(2333)
{
if(val[now]==k){splay(p,now);return now;}
now=ch[now][val[now]<k];
}
}
inline int Pre(int p)
{
int now=ch[root[p]][0];
while(ch[now][1])now=ch[now][1];
return now;
}
inline int Nxt(int p)
{
int now=ch[root[p]][1];
while(ch[now][0])now=ch[now][0];
return now;
}
inline void del(int p,int k)
{
int now=find(p,k);
if(cnt[now]>1){cnt[now]--;up(now);return;}
if(!ch[now][0]&&!ch[now][1]){clear(now);root[p]=0;return;}
if(!ch[now][0])
{
int x=ch[now][1];
root[p]=x;fa[x]=0;
return;
}
if(!ch[now][1])
{
int x=ch[now][0];
root[p]=x;fa[x]=0;
return;
}
int x=Pre(p);
splay(p,x);
ch[x][1]=ch[now][1],fa[ch[now][1]]=x;
clear(now); up(x);
}
inline int pre(int p,int k)
{
int now=root[p],res=-inf;
while(now)
{
if(val[now]<k)
{
res=max(res,val[now]);
now=ch[now][1];
}
else now=ch[now][0];
}
return res;
}
inline int nxt(int p,int k)
{
int now=root[p],res=inf;
while(now)
{
if(val[now]>k)
{
res=min(res,val[now]);
now=ch[now][0];
}
else now=ch[now][1];
}
return res;
}
}
void build(int p,int l,int r)
{
for(int i=l;i<=r;i++)Splay::insert(p,a[i]);
if(l==r)return;
int mid=(l+r)>>1;
build(ls(p),l,mid);build(rs(p),mid+1,r);
}
void change(int p,int l,int r,int pos,int k)
{
Splay::del(p,a[pos]);Splay::insert(p,k);
if(l==r){a[pos]=k;return;}
int mid=(l+r)>>1;
if(pos<=mid)change(ls(p),l,mid,pos,k);
else change(rs(p),mid+1,r,pos,k);
}
int queryrk(int p,int l,int r,int ql,int qr,int k)
{
if(l>=ql&&r<=qr)return Splay::getrk(p,k);
int mid=(l+r)>>1,res=0;
if(ql<=mid)res+=queryrk(ls(p),l,mid,ql,qr,k);
if(qr>mid)res+=queryrk(rs(p),mid+1,r,ql,qr,k);
return res;
}
int querypre(int p,int l,int r,int ql,int qr,int k)
{
if(l>=ql&&r<=qr)return Splay::pre(p,k);
int mid=(l+r)>>1,res=-inf;
if(ql<=mid)res=max(res,querypre(ls(p),l,mid,ql,qr,k));
if(qr>mid)res=max(res,querypre(rs(p),mid+1,r,ql,qr,k));
return res;
}
int querynxt(int p,int l,int r,int ql,int qr,int k)
{
if(l>=ql&&r<=qr)return Splay::nxt(p,k);
int mid=(l+r)>>1,res=inf;
if(ql<=mid)res=min(res,querynxt(ls(p),l,mid,ql,qr,k));
if(qr>mid)res=min(res,querynxt(rs(p),mid+1,r,ql,qr,k));
return res;
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)a[i]=read();
build(1,1,n);
while(m--)
{
int op=read();
if(op==1)
{
int l=read(),r=read(),k=read();
printf("%d
",queryrk(1,1,n,l,r,k)+1);
}
if(op==2)
{
int ql=read(),qr=read(),k=read();
int l=0,r=1e8,res=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(queryrk(1,1,n,ql,qr,mid)<k)res=mid,l=mid+1;
else r=mid-1;
}
printf("%d
",res);
}
if(op==3)
{
int pos=read(),k=read();
change(1,1,n,pos,k);
}
if(op==4)
{
int l=read(),r=read(),k=read();
printf("%d
",querypre(1,1,n,l,r,k));
}
if(op==5)
{
int l=read(),r=read(),k=read();
printf("%d
",querynxt(1,1,n,l,r,k));
}
}
return 0;
}