2021.08.10 静态区间第k小
离散化后用可持久化权值线段树处理。
查询的时候比较第r个版本和第l-1个版本的信息,若左结点cnt之差>=k,说明答案在左结点,递归query(左结点,k),否则答案在右结点,递归query(右结点,k-左结点cnt之差)。
可持久化线段树的写法参考:2021.08.10 可持久化线段树 - ANJHZ - 博客园 (cnblogs.com)
代码对应的模板是洛谷 P3834 【模板】可持久化线段树 2:
#include <bits/stdc++.h> using namespace std; const int N=2e5+11; const int M=2e5+11; int n,m,tot,top,root[N],nys[N]; struct seq { int ord,val,ys; }a[N]; struct CharimanTree { int l,r,cnt; }t[N<<5]; int cmp1(const struct seq &p,const struct seq &q){return p.val<q.val;} int cmp2(const struct seq &p,const struct seq &q){return p.ord<q.ord;} int buildtree(int l,int r) { int now=++top; if(l==r) return now; int mid=(l+r)/2; t[now].l=buildtree(l,mid); t[now].r=buildtree(mid+1,r); return now; } int clone(int now) { t[++top]=t[now]; return top; } void update(int now) { t[now].cnt=0; if(t[now].l) t[now].cnt+=t[t[now].l].cnt; if(t[now].r) t[now].cnt+=t[t[now].r].cnt; } int modify(int now,int l,int r,int pos,int pls) { now=clone(now); if(l==r) { t[now].cnt+=pls; return now; } int mid=(l+r)/2; if(pos<=mid) t[now].l=modify(t[now].l,l,mid,pos,pls); else t[now].r=modify(t[now].r,mid+1,r,pos,pls); update(now); return now; } int query(int rnow,int lnow,int l,int r,int k) { if(t[rnow].cnt-t[lnow].cnt<k) return -2e9; if(l==r) return l; int mid=(l+r)/2; if(t[t[rnow].l].cnt-t[t[lnow].l].cnt>=k) return query(t[rnow].l,t[lnow].l,l,mid,k); else return query(t[rnow].r,t[lnow].r,mid+1,r,k-(t[t[rnow].l].cnt-t[t[lnow].l].cnt)); } int main() { int i,l,r,k; scanf("%d%d",&n,&m); for(i=1;i<=n;i++) { scanf("%d",&a[i].val); a[i].ord=i; } sort(a+1,a+n+1,cmp1); for(i=1;i<=n;i++) { if(i==1||a[i].val!=a[i-1].val) a[i].ys=++tot,nys[tot]=a[i].val; else a[i].ys=tot; } sort(a+1,a+n+1,cmp2); root[0]=buildtree(1,tot); for(i=1;i<=n;i++)root[i]=modify(root[i-1],1,tot,a[i].ys,1); for(i=1;i<=m;i++) { scanf("%d%d%d",&l,&r,&k); printf("%d\n",nys[query(root[r],root[l-1],1,tot,k)]); } return 0; }
浙公网安备 33010602011771号