1. 程式人生 > >【9018:2208】可持久化線段樹2

【9018:2208】可持久化線段樹2

body stat lin nbsp return == tro mst tdi

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

【9018:2208】可持久化線段樹2