您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询 x在区间内的排名;
2.查询区间内排名为 k 的值;
3.修改某一位置上的数值;
4.查询 x 在区间内的前趋(前趋定义为小于 x,且最大的数);
5.查询 x 在区间内的后继(后继定义为大于 x,且最小的数)。
第一行两个数 n,m,表示长度为 n 的有序序列和 m 个操作。
第二行有 n个数,表示有序序列。
下面有 m 行,每行第一个数表示操作类型:
1.之后有三个数 l,r,x表示查询 x在区间 [l,r] 的排名;
2.之后有三个数 l,r,k表示查询区间 [l,r]内排名为 k的数;
3.之后有两个数 pos,x表示将 pos位置的数修改为 x;
4.之后有三个数 l,r,x表示查询区间 [l,r]内 x 的前趋;
5.之后有三个数 l,r,x表示查询区间 [l,r]内 x 的后继。
对于操作 1,2,4,5各输出一行,表示查询结果。
非常经典的树套树题目,这里采用的是线段树套平衡树的做法
对于操作一,我们考虑查询每一分区间小于查询值的数的数量累加起来+1即可,查询过程只需要将其严格次小前缀转到根即可
对于操作二,我们考虑二分一个数,然后参照操作一的做法,查询所有小于等于二分值的数的数量,可以明白,这是单调递增的,故二分可行,注意与操作一不一样的是这里我们需要将非严格次小前缀转到根
对于操作三,直接对每一包含该位置的区间一次删除,一次插入即可
对于操作四,查询每一分区间的严格次小前缀,取较大值
对于操作五,查询每一分区间的严格次大后缀,取较小值
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n,m,a[50005],root[200005],sign,ans,op,sum;
struct Tree
{
int ch[2],fa;
int recy,sum;
int v;
}tree[1650005];
int crepoint(int v,int fa)
{
sign++;
tree[sign].v=v;
tree[sign].fa=fa;
tree[sign].recy=tree[sign].sum=1;
return sign;
}
int whoson(int x)
{
return (tree[tree[x].fa].ch[0]==x)?0:1;
}
void connect(int x,int fa,int son)
{
tree[x].fa=fa;
tree[fa].ch[son]=x;
}
void push_up(int k)
{
tree[k].sum=tree[tree[k].ch[0]].sum+tree[tree[k].ch[1]].sum+tree[k].recy;
}
void rotate(int x)
{
int y=tree[x].fa;
int mroot=tree[y].fa;
int yson=whoson(x);
int mrootson=whoson(y);
int B=tree[x].ch[yson^1];
connect(B,y,yson);
connect(y,x,yson^1);
connect(x,mroot,mrootson);
push_up(y);
push_up(x);
}
void Splay(int x,int to,int k)
{
while(tree[x].fa!=to)
{
int y=tree[x].fa,z=tree[y].fa;
if(z!=to)
{
if(whoson(x)^whoson(y)) rotate(x);
else rotate(y);
}
rotate(x);
}
if(!to) root[k]=x;
}
void find(int nowroot,int v,int k)
{
int now=nowroot;
while(now)
{
if(v==tree[now].v)
{
Splay(now,0,k);
return ;
}
int nex=(v1)
{
tree[nowroot].recy--;
tree[nowroot].sum--;
return ;
}
int ls=tree[nowroot].ch[0],rs=tree[nowroot].ch[1];
if(!ls&&!rs)
{
nowroot=0;
return ;
}
if(!ls)
{
nowroot=rs;
tree[rs].fa=0;
return ;
}
if(!rs)
{
nowroot=ls;
tree[ls].fa=0;
return ;
}
while(tree[ls].ch[1]) ls=tree[ls].ch[1];
Splay(ls,0,k);
tree[nowroot].ch[1]=rs;
if(rs) tree[rs].fa=nowroot;
}
void build(int k,int l,int r)
{
for(int i=l;i<=r;i++) push(root[k],a[i],k);
if(l==r) return ;
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
int super(int nowroot,int v)
{
int maxx=-0x7fffffff,nows=0;
int now=nowroot;
while(now)
{
if(tree[now].vv) if(minn>tree[now].v) minn=tree[now].v,nows=now;
int nex=(v>1;
if(ql<=mid) ask(k<<1,l,mid,ql,qr,v);
if(mid>1;
if(ql<=mid) ask2(k<<1,l,mid,ql,qr,v);
if(mid>1;
if(x<=mid) change(k<<1,l,mid,x,v1,v2);
else change(k<<1|1,mid+1,r,x,v1,v2);
}
void ask3(int k,int l,int r,int ql,int qr,int v)
{
if(ql<=l&&r<=qr)
{
int now=super(root[k],v);
if(now) Splay(now,0,k);
return ;
}
int mid=(l+r)>>1;
if(ql<=mid) ask3(k<<1,l,mid,ql,qr,v);
if(mid>1;
if(ql<=mid) ask4(k<<1,l,mid,ql,qr,v);
if(mid>1;
sum=0;
ask2(1,1,n,x,y,mid);
if(sum>=z) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d\n",ans);
}
else if(op==3)
{
scanf("%d%d",&x,&y);
change(1,1,n,x,a[x],y);
a[x]=y;
}
else if(op==4)
{
scanf("%d%d%d",&x,&y,&z);
ans=-0x7fffffff;
ask3(1,1,n,x,y,z);
printf("%d\n",ans);
}
else
{
scanf("%d%d%d",&x,&y,&z);
ans=0x7fffffff;
ask4(1,1,n,x,y,z);
printf("%d\n",ans);
}
}
}