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数组映射为原数
欢迎各位大佬参观,提出建议和指出错误
感觉像是给自己抄模板用的