[BZOJ 3196] 二逼平衡树
Link:
Solution:
最直观的的思路是用线段树套平衡树
不过一看到区间第$k$大就又忍不住去写最近刚练的带修改主席树了
感觉自己数据结构题灵活变通的能力还不够强啊,一开始$naive$得觉得不好算排名……
区间第$k$大和修改的操作和$Dynamic Rankings$那道经典题完全相同
对于排名只要利用每个节点的$cnt$计算小于等于$k-1$的个数就能算出$k$的排名了
而后面两个询问完全可以用前两个操作求出:
先算出前驱/后继的排名$t$,再求第$t$大的值就行了
Tip:注意离散化时要包含所有询问中出现的值,否则$lower\_ bound$时会出锅……
Code:
#include <bits/stdc++.h> using namespace std; const int MAXN=5e4+10; struct Query{int l,r,k,op;}qry[MAXN]; struct PrTree{int ls,rs,cnt;}seg[MAXN*100]; int n,m,dat[MAXN],dsp[MAXN*6],rt[MAXN],L[MAXN],R[MAXN],cntl,cntr,tot,cnt; int lowbit(int x){return x&(-x);} int idx(int x) {return lower_bound(dsp+1,dsp+tot+1,x)-dsp;} void Update(int &cur,int pos,int val,int l,int r) { if(!cur) cur=++cnt; seg[cur].cnt+=val; if(l==r) return;int mid=(l+r)>>1; if(pos<=mid) Update(seg[cur].ls,pos,val,l,mid); else Update(seg[cur].rs,pos,val,mid+1,r); } int Query(int cur,int pos,int l,int r) { if(l==r) return seg[cur].cnt; int mid=(l+r)>>1; if(pos<=mid) return Query(seg[cur].ls,pos,l,mid); else return Query(seg[cur].rs,pos,mid+1,r)+seg[seg[cur].ls].cnt; } int Kth(int k,int l,int r) { if(l==r) return l; int mid=(l+r)>>1,sum=0; for(int i=1;i<=cntl;i++) sum-=seg[seg[L[i]].ls].cnt; for(int i=1;i<=cntr;i++) sum+=seg[seg[R[i]].ls].cnt; if(k<=sum) { for(int i=1;i<=cntl;i++) L[i]=seg[L[i]].ls; for(int i=1;i<=cntr;i++) R[i]=seg[R[i]].ls; return Kth(k,l,mid); } else { for(int i=1;i<=cntl;i++) L[i]=seg[L[i]].rs; for(int i=1;i<=cntr;i++) R[i]=seg[R[i]].rs; return Kth(k-sum,mid+1,r); } } void upd(int pos,int val) { for(int i=pos;i<=n;i+=lowbit(i)) Update(rt[i],dat[pos],val,1,tot); } int find_rank(int l,int r,int k) { int sum=0; for(int i=l-1;i;i-=lowbit(i)) sum-=Query(rt[i],k,1,tot); for(int i=r;i;i-=lowbit(i)) sum+=Query(rt[i],k,1,tot); return sum; } int find_kth(int l,int r,int k) { cntl=cntr=0; for(int i=l-1;i;i-=lowbit(i)) L[++cntl]=rt[i]; for(int i=r;i;i-=lowbit(i)) R[++cntr]=rt[i]; return dsp[Kth(k,1,tot)]; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&dat[i]),dsp[++tot]=dat[i]; for(int i=1;i<=m;i++) { scanf("%d%d%d",&qry[i].op,&qry[i].l,&qry[i].r); if(qry[i].op==3) dsp[++tot]=qry[i].r; else {//一定要将全部数据录入离散化数组! scanf("%d",&qry[i].k); if(qry[i].op!=2) dsp[++tot]=qry[i].k; } } sort(dsp+1,dsp+tot+1);tot=unique(dsp+1,dsp+tot+1)-dsp-1; for(int i=1;i<=n;i++) dat[i]=idx(dat[i]),upd(i,1); for(int i=1;i<=m;i++) { int l=qry[i].l,r=qry[i].r,k=qry[i].k; switch(qry[i].op) { case 1:printf("%d\n",find_rank(l,r,idx(k)-1)+1);break; case 2:printf("%d\n",find_kth(l,r,k));break; case 3:upd(l,-1);dat[l]=idx(r);upd(l,1);break; case 4: { int t=find_rank(l,r,idx(k)-1); if(!t){puts("-2147483647");break;} printf("%d\n",find_kth(l,r,t));break; } case 5: { int t=find_rank(l,r,idx(k)); if(t==r-l+1){puts("2147483647");break;} printf("%d\n",find_kth(l,r,t+1));break; } } } return 0; }