求序列中第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 }