pku2104

传送门: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\n",list[ans]);
60     }
61 }
62 int main()
63 {
64     init();
65     solve();
66 }
View Code

 

posted @ 2016-06-17 21:43  ACist  阅读(203)  评论(0编辑  收藏  举报