传送门:http://poj.org/problem?id=2104
题目大意:给定一个长度为N的数组{A[i]},你的任务是解决Q个询问。每次询问在A[l], A[l+1], ...... , A[r]的子区间(
下标从1开始)内,第K大的数是多少。这里的第K大数可以理解为,将给定子数组拿出来按升序排序,其中排在第K
个的数。注意询问操作并不更改原数组。
题解:水题,主席树回顾-----------
代码:
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<cmath> 6 #define maxn 100005 7 using namespace std; 8 int a[maxn],list[maxn]; 9 int root[maxn],ls[maxn*40],rs[maxn*40],sum[maxn*40]; 10 int n,m,sz; 11 int read() 12 { 13 int x=0; char ch; bool bo=0; 14 while (ch=getchar(),ch<'0'||ch>'9') if (ch=='-') bo=1; 15 while (x=x*10+ch-'0',ch=getchar(),ch>='0'&&ch<='9'); 16 if (bo) return -x; return x; 17 } 18 void ins(int l,int r,int x,int &y,int val) 19 { 20 y=++sz; sum[y]=sum[x]+1; 21 if (l==r) return; 22 ls[y]=ls[x]; rs[y]=rs[x]; 23 int mid=(l+r)>>1; 24 if (val<=mid) ins(l,mid,ls[x],ls[y],val); 25 else ins(mid+1,r,rs[x],rs[y],val); 26 } 27 void init() 28 { 29 n=read(); m=read(); 30 for (int i=1; i<=n; i++) list[i]=a[i]=read(); 31 sort(list+1,list+1+n); 32 for (int i=1; i<=n; i++) a[i]=lower_bound(list+1,list+1+n,a[i])-list; 33 for (int i=1; i<=n; i++) ins(1,n,root[i-1],root[i],a[i]); 34 } 35 int query(int L,int R,int k) 36 { 37 int l=1,r=n,x=root[L-1],y=root[R]; 38 while (l!=r) 39 { 40 int tmp=sum[ls[y]]-sum[ls[x]]; 41 int mid=(l+r)>>1; 42 if (k<=tmp) 43 { 44 r=mid,x=ls[x],y=ls[y]; 45 } 46 else 47 { 48 l=mid+1,k-=tmp,x=rs[x],y=rs[y]; 49 } 50 } 51 return l; 52 } 53 void solve() 54 { 55 for (int i=1; i<=m; i++) 56 { 57 int l=read(),r=read(),k=read(); 58 int ans=query(l,r,k); 59 printf("%d ",list[ans]); 60 } 61 } 62 int main() 63 { 64 init(); 65 solve(); 66 }