1. 程式人生 > 其它 >2021.08.10 靜態區間第k小

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; }