首页 > 代码库 > poj 2104:K-th Number(划分树,经典题)
poj 2104:K-th Number(划分树,经典题)
K-th Number
Time Limit: 20000MS | Memory Limit: 65536K | |
Total Submissions: 35653 | Accepted: 11382 | |
Case Time Limit: 2000MS |
Description
You are working for Macrohard company in data structures department. After failing your previous task about key insertion you were asked to write a new data structure that would be able to return quickly k-th order statistics in the array segment.
That is, given an array a[1...n] of different integer numbers, your program must answer a series of questions Q(i, j, k) in the form: "What would be the k-th number in a[i...j] segment, if this segment was sorted?"
For example, consider the array a = (1, 5, 2, 6, 3, 7, 4). Let the question be Q(2, 5, 3). The segment a[2...5] is (5, 2, 6, 3). If we sort this segment, we get (2, 3, 5, 6), the third number is 5, and therefore the answer to the question is 5.
That is, given an array a[1...n] of different integer numbers, your program must answer a series of questions Q(i, j, k) in the form: "What would be the k-th number in a[i...j] segment, if this segment was sorted?"
For example, consider the array a = (1, 5, 2, 6, 3, 7, 4). Let the question be Q(2, 5, 3). The segment a[2...5] is (5, 2, 6, 3). If we sort this segment, we get (2, 3, 5, 6), the third number is 5, and therefore the answer to the question is 5.
Input
The first line of the input file contains n --- the size of the array, and m --- the number of questions to answer (1 <= n <= 100 000, 1 <= m <= 5 000).
The second line contains n different integer numbers not exceeding 109 by their absolute values --- the array for which the answers should be given.
The following m lines contain question descriptions, each description consists of three numbers: i, j, and k (1 <= i <= j <= n, 1 <= k <= j - i + 1) and represents the question Q(i, j, k).
The second line contains n different integer numbers not exceeding 109 by their absolute values --- the array for which the answers should be given.
The following m lines contain question descriptions, each description consists of three numbers: i, j, and k (1 <= i <= j <= n, 1 <= k <= j - i + 1) and represents the question Q(i, j, k).
Output
For each question output the answer to it --- the k-th number in sorted a[i...j] segment.
Sample Input
7 3 1 5 2 6 3 7 4 2 5 3 4 4 1 1 7 3
Sample Output
5 6 3
Hint
This problem has huge input,so please use c-style input(scanf,printf),or you may got time limit exceed.
Source
Northeastern Europe 2004, Northern Subregion
划分树,经典题。
关于划分树的解释可以参考博文:sdut 2610:Boring Counting(第四届山东省省赛原题,划分树 + 二分)。这个属于高级点的应用,至于基础的介绍,我就不多写了(懒人一个。。),可以参考这篇博客,介绍的很详细:划分树。
这里简单一提,划分树的主要作用是用来求“区间内第k大的元素”,这道题属于经典应用,就是赤裸裸的求一个区间内第k大的数。题目“K-th Number”已经标明了这种含义。
因为之前做过一道划分树的题,所以无耻的套用了上道题的代码,然后就改了改就无耻的过了。O_o,原谅我吧。
代码:
1 #include <iostream>
2 #include <stdio.h>
3 #include <algorithm>
4 using namespace std;
5 #define MAXN 100005
6 struct Divide_tree{ //划分树的结构(4个数组,2个操作)
7 int arr[MAXN]; //原数组
8 int sorted[MAXN]; //排序后数组
9 int sum[20][MAXN]; //记录第i层1~j划分到左子树的元素个数(包括j)
10 int dat[20][MAXN]; //记录第i层元素序列
11 void build(int c,int L,int R) //建树,主要是建立sum[][]和dat[][]数组
12 {
13 int mid = (L+R)>>1;
14 int lsame = mid-L+1; //lsame用来记录和中间值val_mid相等的,且可以分到左孩子的数的个数
15 //简单来说就是可以放入左孩子的,与中间值val_mid相等的数的个数
16 int lp=L,rp=mid+1; //当前节点的左孩子和右孩子存数的起点
17 for(int i=L;i<mid;i++) //获得一开始的lsame
18 if(sorted[i]<sorted[mid])
19 lsame--;
20 for(int i=L;i<=R;i++){ //从前往后遍历一遍,
21 //确定当前节点区间内的所有元素的归属(放在左孩子或者放在右孩子)
22 if(i==L) sum[c][i]=0;
23 else sum[c][i]=sum[c][i-1];
24 if(dat[c][i]<sorted[mid]){ //当前元素比中间值val_mid小,放入左孩子
25 dat[c+1][lp++] = dat[c][i];
26 sum[c][i]++;
27 }
28 else if(dat[c][i]>sorted[mid]) //当前元素比中间值val_mid大,放入右孩子
29 dat[c+1][rp++] = dat[c][i];
30 else{ //当前元素值与中间值val_mid相等,根据lsame数判断放入左孩子还是右孩子
31 if(lsame){
32 lsame--;
33 sum[c][i]++;
34 dat[c+1][lp++]=sorted[mid];
35 }
36 else{
37 dat[c+1][rp++]=sorted[mid];
38 }
39 }
40 }
41 if(L==R) return ; //递归出口,遇到叶子节点
42 build(c+1,L,mid); //递归进入左孩子区间
43 build(c+1,mid+1,R); //递归进入右孩子区间
44 }
45 int query(int c,int L,int R,int ql,int qr,int k)
46 {
47 //c为树的层数,L,R为当前节点的区间范围,ql,qr为查询的区间范围,k为查询范围内第k大的数
48 if(L==R) //递归出口,返回第k大的数
49 return dat[c][L];
50 int s; //记录[L,ql-1]中进入左孩子的元素的个数
51 int ss; //记录[ql,qr]中进入左孩子的元素的个数
52 int mid=(L+R)>>1;
53 if(L==ql){ //端点重合的情况,单独考虑
54 s=0;
55 ss=sum[c][qr];
56 }
57 else {
58 s=sum[c][ql-1];
59 ss=sum[c][qr]-s;
60 }
61 if(k<=ss) //左孩子的元素个数大于k个,说明第k大的元素一定在左孩子区间中,到左孩子中查询
62 return query(c+1,L,mid,L+s,L+s+ss-1,k);
63 else
64 return query(c+1,mid+1,R,mid+1+ql-s-L,mid+1+qr-s-ss-L,k-ss);
65 }
66 };
67 Divide_tree tree; //定义划分树
68 int main()
69 {
70 int i,L,R,N,M,k;
71 scanf("%d%d",&N,&M);
72 for(i=1;i<=N;i++){ //输入
73 scanf("%d",&tree.arr[i]);
74 tree.sorted[i]=tree.dat[0][i]=tree.arr[i];
75 }
76 sort(tree.sorted+1,tree.sorted+N+1);
77 tree.build(0,1,N);
78 for(i=1;i<=M;i++){ //M次询问
79 scanf("%d%d%d",&L,&R,&k);
80 printf("%d\n",tree.query(0,1,N,L,R,k));
81 }
82
83 return 0;
84 }
Freecode : www.cnblogs.com/yym2013
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。