2208: 【模板】可持久化线段树2
时间限制: 3 Sec 内存限制: 256 MB提交: 30 解决: 12
[提交][状态][讨论版]
题目描述
静态区间第K小问题是典型的主席树模板。
在这个问题中,你需要实现对区间第K小的查询。
输入
第1行,输入两个正整数n,m,表示数列长度,查询次数。
第2行,n个整数表示数列ai。
接下来m行,每行3个正整数l,r,k表示查询[l,r]内的第k小数。(1<=l<=r<=n,1<=k<=r-l+1)
输出
输出m行,每行1个整数表示答案。
样例输入
5 5
25957 6405 15770 26287 26465
2 2 1
3 4 1
4 5 1
1 2 2
4 4 1
样例输出
6405
15770
26287
25957
26287
提示
对于100%的数据满足:1≤N,M≤5?1051 \leq N, M \leq 2\cdot 10^5
对于数列中的所有数aia_i,均满足?109≤ai≤109-{10}^9 \leq a_i \leq {10}^9
代码如下:
#include<cstdio> #include<iostream> #include<algorithm> #define MN 500005 #define MM 10000005 using namespace std; int n,q,v[MN],rk[MN],vv[MN],cnt,T[MM],ls[MM],rs[MM],rt[MM]; bool cmp(int x,int y){return v[x]<v[y];} void update(int &k,int l,int r,int v){ ls[++cnt]=ls[k],rs[cnt]=rs[k],k=cnt; if(l==r){T[k]=1;return;} int mid=(l+r)>>1; if(v<=mid) update(ls[k],l,mid,v); else update(rs[k],mid+1,r,v); T[k]=T[ls[k]]+T[rs[k]]; } int query(int k,int l,int r,int ql,int qr){ if(l==r) return l; int mid=(l+r)>>1; if(k<=T[ls[qr]]-T[ls[ql]]) return query(k,l,mid,ls[ql],ls[qr]); else return query(k-=T[ls[qr]]-T[ls[ql]],mid+1,r,rs[ql],rs[qr]); } int main() { scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) scanf("%d",&v[i]),rk[i]=i; sort(rk+1,rk+1+n,cmp); for(int i=1;i<=n;i++) vv[rk[i]]=i; //for(int i=1;i<=n;i++) printf("%d\n",rk[i]); for(int i=1;i<=n;i++) rt[i]=rt[i-1],update(rt[i],1,n,vv[i]); for(int i=1;i<=q;i++){ int x,y,k; scanf("%d%d%d",&x,&y,&k); printf("%d\n",v[rk[query(k,1,n,rt[x-1],rt[y])]]); } return 0; }