Description
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1. 查询
2. 查询区间内排名为
3. 修改某一位值上的数值
4. 查询
5. 查询
Input
第一行两个数
第二行有
下面有
若
若
若
若
若
Output
对于操作
Sample Input
9 6
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5
Sample Output
2
4
3
4
9
HINT
n 和m 的数据范围:n,m<=50000 - 序列中每个数的数据范围:
[0,1e8] - 虽然原题没有,但事实上
5 操作的k 可能为负数
Source
思路
线段树套平衡树。
代码
#include <cstdio>
const int maxn=50000;
const int maxs=4000000;
const int inf=0x3f3f3f3f;
struct splay_tree
{
int val[maxs],fa[maxs],son[2][maxs],cnt[maxs],size[maxs],tot;
inline int t(int x)
{
return son[1][fa[x]]==x;
}
inline int updata(int x)
{
return size[x]=size[son[0][x]]+size[son[1][x]]+cnt[x];
}
inline int rotate(int x)
{
int k=t(x),f=fa[x];
if(fa[f])
{
son[t(f)][fa[f]]=x;
}
fa[x]=fa[f];
if(son[!k][x])
{
fa[son[!k][x]]=f;
}
son[k][f]=son[!k][x];
fa[f]=x;
son[!k][x]=f;
updata(f);
updata(x);
return 0;
}
inline int splay(int &root,int x,int c)
{
while(fa[x]!=c)
{
int f=fa[x];
if(fa[f]==c)
{
rotate(x);
}
else if(t(x)==t(f))
{
rotate(f);
rotate(x);
}
else
{
rotate(x);
rotate(x);
}
}
if(!c)
{
root=x;
}
return 0;
}
inline int getkth(int root,int x)
{
int now=root;
while(now)
{
if((size[son[0][now]]+cnt[now]>=x)&&(size[son[0][now]]<x))
{
return now;
}
else if(size[son[0][now]]+cnt[now]<x)
{
x-=size[son[0][now]]+1;
now=son[1][now];
}
else
{
now=son[0][now];
}
}
return 0;
}
inline int ins(int &root,int x)
{
if(!root)
{
++tot;
fa[tot]=son[0][tot]=son[1][tot]=0;
size[tot]=cnt[tot]=1;
val[tot]=x;
root=tot;
return 0;
}
int now=root;
while(now)
{
if(val[now]==x)
{
cnt[now]++;
splay(root,now,0);
return 0;
}
else
{
int k=val[now]<x;
if(!son[k][now])
{
++tot;
son[k][now]=tot;
fa[tot]=now;
son[0][tot]=son[1][tot]=0;
size[tot]=cnt[tot]=1;
val[tot]=x;
splay(root,tot,0);
return 0;
}
else
{
now=son[k][now];
}
}
}
return 0;
}
inline int del(int &root,int x)
{
int now=root;
while(now)
{
if(val[now]==x)
{
break;
}
else
{
now=son[val[now]<x][now];
}
}
if(cnt[now]>1)
{
--cnt[now];
splay(root,now,0);
return 0;
}
splay(root,now,0);
if((!son[0][now])&&(!son[1][now]))
{
root=0;
}
else if(!son[0][now])
{
root=son[1][now];
fa[son[1][now]]=0;
}
else if(!son[1][now])
{
root=son[0][now];
fa[son[0][now]]=0;
}
else
{
int w=son[0][root];
while(son[1][w])
{
w=son[1][w];
}
splay(root,w,root);
root=w;
fa[w]=0;
son[1][w]=son[1][now];
fa[son[1][now]]=w;
updata(w);
}
return 0;
}
inline int getrank(int &root,int x)
{
int now=root,ans=0;
while(now)
{
if(val[now]==x)
{
ans+=size[son[0][now]];
break;
}
else
{
if(val[now]<x)
{
ans+=size[son[0][now]]+cnt[now];
now=son[1][now];
}
else
{
now=son[0][now];
}
}
}
return ans;
}
int getpre(int now,int x)
{
if(!now)
{
return 0;
}
else if(val[now]<x)
{
int w=getpre(son[1][now],x);
if(w)
{
return w;
}
else
{
return now;
}
}
else
{
return getpre(son[0][now],x);
}
}
int getnext(int now,int x)
{
if(!now)
{
return 0;
}
else if(val[now]>x)
{
int w=getnext(son[0][now],x);
if(w)
{
return w;
}
else
{
return now;
}
}
else
{
return getnext(son[1][now],x);
}
}
};
int n,r[maxn+10];
inline int max(int a,int b)
{
return a<b?b:a;
}
inline int min(int a,int b)
{
return a<b?a:b;
}
struct segment_tree
{
int root[maxn<<2];
splay_tree st;
int build(int now,int left,int right)
{
for(register int i=left; i<=right; ++i)
{
st.ins(root[now],r[i]);
}
if(left==right)
{
return 0;
}
int mid=(left+right)>>1;
build(now<<1,left,mid);
build(now<<1|1,mid+1,right);
return 0;
}
int getrank(int now,int left,int right,int askl,int askr,int v)
{
if((askl<=left)&&(right<=askr))
{
return st.getrank(root[now],v);
}
int mid=(left+right)>>1,res=0;
if(askl<=mid)
{
res+=getrank(now<<1,left,mid,askl,askr,v);
}
if(mid<askr)
{
res+=getrank(now<<1|1,mid+1,right,askl,askr,v);
}
return res;
}
int modify(int now,int left,int right,int pos,int v)
{
st.ins(root[now],v);
st.del(root[now],r[pos]);
if(left==right)
{
return 0;
}
int mid=(left+right)>>1;
if(pos<=mid)
{
modify(now<<1,left,mid,pos,v);
}
else
{
modify(now<<1|1,mid+1,right,pos,v);
}
return 0;
}
int getpre(int now,int left,int right,int askl,int askr,int v)
{
if((askl<=left)&&(right<=askr))
{
return st.val[st.getpre(root[now],v)];
}
int mid=(left+right)>>1,res=0;
if(askl<=mid)
{
res=max(res,getpre(now<<1,left,mid,askl,askr,v));
}
if(mid<askr)
{
res=max(res,getpre(now<<1|1,mid+1,right,askl,askr,v));
}
return res;
}
int getnext(int now,int left,int right,int askl,int askr,int v)
{
if((askl<=left)&&(right<=askr))
{
int f=st.getnext(root[now],v);
if(!f)
{
return inf;
}
return st.val[f];
}
int mid=(left+right)>>1,res=inf;
if(askl<=mid)
{
res=min(res,getnext(now<<1,left,mid,askl,askr,v));
}
if(mid<askr)
{
res=min(res,getnext(now<<1|1,mid+1,right,askl,askr,v));
}
return res;
}
};
segment_tree st;
int m,opt,a,b,c;
int main()
{
scanf("%d%d",&n,&m);
for(register int i=1; i<=n; ++i)
{
scanf("%d",&r[i]);
}
st.build(1,1,n);
while(m--)
{
scanf("%d%d%d",&opt,&a,&b);
if(opt==3)
{
st.modify(1,1,n,a,b);
r[a]=b;
continue;
}
scanf("%d",&c);
if(opt==1)
{
printf("%d\n",st.getrank(1,1,n,a,b,c)+1);
}
else if(opt==2)
{
int left=0,right=1e8;
while(left<=right)
{
int mid=(left+right)>>1;
if(st.getrank(1,1,n,a,b,mid)<c)
{
left=mid+1;
}
else
{
right=mid-1;
}
}
printf("%d\n",left-1);
}
else if(opt==4)
{
printf("%d\n",st.getpre(1,1,n,a,b,c));
}
else
{
printf("%d\n",st.getnext(1,1,n,a,b,c));
}
}
return 0;
}