Code:
#include<bits/stdc++.h>
using namespace std;
struct segmenttree
{
int l,r,cnt;
}sgt[8*100000+5];
struct option
{
int op,x;
}opt[100005];
int rk[100005],org[100005],n;
void build(int p,int l,int r)
{
sgt[p].l=l;sgt[p].r=r;
if(l==r)return ;
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
}
void update(int p)
{
sgt[p].cnt=sgt[p<<1].cnt+sgt[p<<1|1].cnt;
}
void change(int p,int k,int d)
{
if(sgt[p].l==sgt[p].r)
{
if(sgt[p].cnt+d>=0)sgt[p].cnt+=d;
return ;
}
int mid=(sgt[p].l+sgt[p].r)>>1;
if(k<=mid)change(p<<1,k,d);
else change(p<<1|1,k,d);
update(p);
}
int getrank(int p,int k)
{
if(sgt[p].l==sgt[p].r)return 1;
int mid=(sgt[p].l+sgt[p].r)>>1;
if(k<=mid)return getrank(p<<1,k);
else return getrank(p<<1|1,k)+sgt[p<<1].cnt;
}
int getval(int p,int k)
{
if(sgt[p].l==sgt[p].r)return sgt[p].l;
if(k<=sgt[p<<1].cnt)return getval(p<<1,k);
else return getval(p<<1|1,k-sgt[p<<1].cnt);
}
int getcnt(int p,int k)
{
if(sgt[p].l==sgt[p].r)return sgt[p].cnt;
int mid=(sgt[p].l+sgt[p].r)>>1;
if(k<=mid)return getcnt(p<<1,k);
else return getcnt(p<<1|1,k);
}
int main()
{
scanf("%d",&n);
int i,sum=0;
for(i=1;i<=n;i++)
{
scanf("%d%d",&opt[i].op,&opt[i].x);
if(opt[i].op!=4)rk[++sum]=opt[i].x;
}
sort(rk+1,rk+sum+1);
int cnt=unique(rk+1,rk+sum+1)-rk;
for(i=1;i<=n;i++)
if(opt[i].op!=4)
{
int val=lower_bound(rk+1,rk+cnt+1,opt[i].x)-rk;
org[val]=opt[i].x;
opt[i].x=val;
}
build(1,1,cnt);
for(i=1;i<=n;i++)
{
int x=opt[i].x,op=opt[i].op;
if(op==1)change(1,x,1);
else if(op==2)change(1,x,-1);
else if(op==3)printf("%d\n",getrank(1,x));
else if(op==4)printf("%d\n",org[getval(1,x)]);
else if(op==5)printf("%d\n",org[getval(1,getrank(1,x)-1)]);
else printf("%d\n",org[getval(1,getrank(1,x)+getcnt(1,x))]);
}
return 0;
}具体思想:
1、离散化维护值域动态开点
2、统计数出现的次数
3、单点修改,单点查询其实这样想树状数组好像也可以,但我不会
具体实现:
先离散化,再线段树维护值域,每一个节点维护这个区间中目前有多少个数
于是增加/删减直接单点修改即可
对于获取排名,getrank(x)实现方法为:
1、若搜索到x,则返回一(排名定义,比x小的数个数+1)
2、若x<=区间中位数,则返回左儿子getrank(x)
3、若非前两种情况,则返回右儿子getrank(x)+左儿子的cnt
对于根据排名获取数,getval(x)实现方法为:
1、若到目标节点,则返回这个节点
2、若x<=左儿子的cnt,则返回左儿子getrank(x)
3、若非前两种情况,则返回右儿子getrank(x-左儿子的cnt)
还有一个辅助操作,getcnt(x)表示获得x出现了几次,具体实现见代码懒得讲
求前驱时,由于返回值为<x的数个数+1,直接返回getval(getrank(x)-1)即可
求后继时,由于要加上x的个数,直接返回getval(getrank(x)+getcnt(x))
注意最后要由org数组映射为原数
欢迎各位大佬参观,提出建议和指出错误
感觉像是给自己抄模板用的

京公网安备 11010502036488号