求序列中第k大的元素(划分树模板)

http://acm.hdu.edu.cn/showproblem.php?pid=4251

n个数,求给定区间中间大小的元素的值

Sample Input
5
5 3 2 4 1
3
1 3
2 4
3 5
5
10 6 4 8 2
3
1 3
2 4
3 5
Sample Output
Case 1:
3
3
2
Case 2:
6
6
4
 1 #include<cstdio>
 2 #include<string>
 3 #include<vector>
 4 #include<algorithm>
 5 #define N 100009
 6 using namespace std;
 7 int n;
 8 int arr[N];//原数据
 9 int od[N];//排序后
10 int lfnum[20][N];//元素所在区间的当前位置进入左孩子的元素的个数
11 int val[20][N];//记录第k层当前位置的元素的值
12 bool cmp(const int &x,const int &y){return arr[x]<arr[y];}
13 void build(int l,int r,int d)
14 {
15     if(l==r) return;
16     int mid=(l+r)>>1,p=0;
17     for(int i=l;i<=r;i++)
18     {
19         if(val[d][i]<=mid)
20         {
21             val[d+1][l+p]=val[d][i];
22             lfnum[d][i]=++p;
23         }
24         else
25         {
26             lfnum[d][i]=p;
27             val[d+1][mid+i+1-l-p]=val[d][i];
28         }
29     }
30     build(l,mid,d+1);
31     build(mid+1,r,d+1);
32 }
33 //求区间[s,e]第k大的元素
34 int query(int s,int e,int k,int l=1,int r=n,int d=0)
35 {
36     if(l==r) return l;
37     int mid=(l+r)>>1,ss,ee;
38     ss=(s==l?0:lfnum[d][s-1]);
39     ee=lfnum[d][e];
40     if(ee-ss>=k) return query(l+ss,l+ee-1,k,l,mid,d+1);
41     return query(mid+1+(s-l-ss),mid+1+(e-l-ee),k-(ee-ss),mid+1,r,d+1);
42 }
43 int main()
44 {
45     int cas=0,m,l,r;
46     while(scanf("%d",&n)!=EOF)
47     {
48         printf("Case %d:\n",++cas);
49         for(int i=1;i<=n;i++) scanf("%d",arr+i),od[i]=i;
50         sort(od+1,od+n+1,cmp);
51         for(int i=1;i<=n;i++) val[0][od[i]]=i;
52         build(1,n,0);
53         scanf("%d",&m);
54         while(m--)
55         {
56             int num,k;
57             scanf("%d%d",&l,&r);
58             k=(r-l)/2+1;//中间大小
59             num=query(l,r,k);
60             int ans=arr[od[num]];
61             printf("%d\n",ans);
62         }
63     }
64 }

 

posted @ 2012-07-17 10:50  qijinbiao1  阅读(492)  评论(0编辑  收藏  举报