K-th Number (POJ_2104) 划分树
2016-02-24 11:31
363 查看
K-th Number
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.
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).
Output
For each question output the answer to it --- the k-th number in sorted a[i...j] segment.
Sample Input
Sample Output
Hint
This problem has huge input,so please use c-style input(scanf,printf),or you may got time limit exceed.
题目大意:给出一系列数,求出给定区间的Kth值。
解题思路:划分树。
先建树,然后进行查询。
建树的思路为快速排序,小于中位数的放到左边,大于的放到右边。设当前区间为[l,r],当前为第i个数,用left[i]记录[l,i]内有多少个数划入左边区间。
查询思路为不断缩小区间,直到为单位区间(l==r)。难点在于如何在当前的大区间中确定小区间,这时就要用到,前面记录的划入左边区间的个数。首先要比较当前查询区间(ll,rr)划入左区间的个数num=left[ll-1]-left[rr]和k值大小,如果k<=num,则Kth值在左曲建,否则在右区间。
sort[ ][2 3 3 4 4 5 5 7 9]
tree[0][3 5 7 3 4 9 4 2 5]
tree[1][3 3 4 4 2][5 7 9 5]
tree[2][3 3 2][4 4][5 5][7 9]
tree[3][3 2][3][4][4][5][5][7][9]
tree[4][2][3][3][4][4][5][5][7][9]
当在左区间时,小区间为( l+num , l+left[rr]-1 ),查询第k值
当在右区间时,小区间为( mid+1+( ll-l-left[ll-1] ) , mid+1+rr-l-left[ll-1] ),查询第(k-left[ll-1])值
参考博文:http://blog.csdn.net/dyx404514/article/details/8731696
代码如下:
#include"cstdio"
#include"iostream"
#include"algorithm"
#define MAXN 100000 + 10
using namespace std;
struct seq{
int order;
int value;
}a[MAXN];
struct node{ //划分树
int val[MAXN]; //存值
int left[MAXN]; //划入左子树的个数
int deep; //深度
}tree[25];
bool cmp(seq a,seq b){
return a.value<b.value;
}
//构建划分树
void Build(int d,int l,int r){
if(l==r) return ;
int mid=(l+r)>>1;
int p=0,t=0;
for(int i=l;i<=r;i++){
if(tree[d].val[i]<=mid){//划入左子树
tree[d+1].val[l+p]=tree[d].val[i];
p++;
tree[d].left[i]=p;
}else{//划入右子树
tree[d+1].val[mid+1+t]=tree[d].val[i];
t++;
tree[d].left[i]=p; //是p不是t
}
}
Build(d+1,l,mid);
Build(d+1,mid+1,r);
}
//在大区间(l,r)中查找小区间(ll,rr)的第k大值
int Query(int d,int l,int r,int ll,int rr,int k){
if(ll==rr) return (tree[d].val[ll]);
int ls=0,rs=0; //ls,rs用于
4000
确定小区间
if(ll>l)
ls=tree[d].left[ll-1];
else ls=0;
int mid=(l+r)>>1;
rs=tree[d].left[rr];
if(rs-ls>=k)
return Query(d+1,l,mid,l+ls,l+rs-1,k);
else
return Query(d+1,mid+1,r,(mid+1)+(ll-l-ls),(mid+1)+rr-l-rs,k-(rs-ls));
if(ll==rr) return tree[d].val[ll];
}
int main(){
int n,m;
int i;
while(scanf("%d%d",&n,&m)!=EOF){
//存值并进行离散化
for(i=1;i<=n;i++){
scanf("%d",&a[i].value);
a[i].order=i;
}
sort(a+1,a+1+n,cmp);
for(i=1;i<=n;i++){
tree[0].val[a[i].order]=i;
}
Build(0,1,n);
while(m--){
int ll,rr,k;
scanf("%d%d%d",&ll,&rr,&k);
printf("%d\n",a[Query(0,1,n,ll,rr,k)].value);
}
}
return 0;
}
Time Limit: 20000MS | Memory Limit: 65536K | |
Total Submissions: 45147 | Accepted: 15021 | |
Case Time Limit: 2000MS |
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.
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).
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.
题目大意:给出一系列数,求出给定区间的Kth值。
解题思路:划分树。
先建树,然后进行查询。
建树的思路为快速排序,小于中位数的放到左边,大于的放到右边。设当前区间为[l,r],当前为第i个数,用left[i]记录[l,i]内有多少个数划入左边区间。
查询思路为不断缩小区间,直到为单位区间(l==r)。难点在于如何在当前的大区间中确定小区间,这时就要用到,前面记录的划入左边区间的个数。首先要比较当前查询区间(ll,rr)划入左区间的个数num=left[ll-1]-left[rr]和k值大小,如果k<=num,则Kth值在左曲建,否则在右区间。
sort[ ][2 3 3 4 4 5 5 7 9]
tree[0][3 5 7 3 4 9 4 2 5]
tree[1][3 3 4 4 2][5 7 9 5]
tree[2][3 3 2][4 4][5 5][7 9]
tree[3][3 2][3][4][4][5][5][7][9]
tree[4][2][3][3][4][4][5][5][7][9]
当在左区间时,小区间为( l+num , l+left[rr]-1 ),查询第k值
当在右区间时,小区间为( mid+1+( ll-l-left[ll-1] ) , mid+1+rr-l-left[ll-1] ),查询第(k-left[ll-1])值
参考博文:http://blog.csdn.net/dyx404514/article/details/8731696
代码如下:
#include"cstdio"
#include"iostream"
#include"algorithm"
#define MAXN 100000 + 10
using namespace std;
struct seq{
int order;
int value;
}a[MAXN];
struct node{ //划分树
int val[MAXN]; //存值
int left[MAXN]; //划入左子树的个数
int deep; //深度
}tree[25];
bool cmp(seq a,seq b){
return a.value<b.value;
}
//构建划分树
void Build(int d,int l,int r){
if(l==r) return ;
int mid=(l+r)>>1;
int p=0,t=0;
for(int i=l;i<=r;i++){
if(tree[d].val[i]<=mid){//划入左子树
tree[d+1].val[l+p]=tree[d].val[i];
p++;
tree[d].left[i]=p;
}else{//划入右子树
tree[d+1].val[mid+1+t]=tree[d].val[i];
t++;
tree[d].left[i]=p; //是p不是t
}
}
Build(d+1,l,mid);
Build(d+1,mid+1,r);
}
//在大区间(l,r)中查找小区间(ll,rr)的第k大值
int Query(int d,int l,int r,int ll,int rr,int k){
if(ll==rr) return (tree[d].val[ll]);
int ls=0,rs=0; //ls,rs用于
4000
确定小区间
if(ll>l)
ls=tree[d].left[ll-1];
else ls=0;
int mid=(l+r)>>1;
rs=tree[d].left[rr];
if(rs-ls>=k)
return Query(d+1,l,mid,l+ls,l+rs-1,k);
else
return Query(d+1,mid+1,r,(mid+1)+(ll-l-ls),(mid+1)+rr-l-rs,k-(rs-ls));
if(ll==rr) return tree[d].val[ll];
}
int main(){
int n,m;
int i;
while(scanf("%d%d",&n,&m)!=EOF){
//存值并进行离散化
for(i=1;i<=n;i++){
scanf("%d",&a[i].value);
a[i].order=i;
}
sort(a+1,a+1+n,cmp);
for(i=1;i<=n;i++){
tree[0].val[a[i].order]=i;
}
Build(0,1,n);
while(m--){
int ll,rr,k;
scanf("%d%d%d",&ll,&rr,&k);
printf("%d\n",a[Query(0,1,n,ll,rr,k)].value);
}
}
return 0;
}
相关文章推荐
- 初学ACM - 组合数学基础题目PKU 1833
- 线段树题集
- POJ ACM 1001
- POJ ACM 1002
- 1611:The Suspects
- POJ1089 区间合并
- POJ 2635 The Embarrassed Cryptographe
- POJ 3292 Semi-prime H-numbers
- POJ 2773 HAPPY 2006
- POJ 3090 Visible Lattice Points
- POJ-2409-Let it Bead&&NYOJ-280-LK的项链
- POJ-1695-Magazine Delivery-dp
- POJ1523 SPF dfs
- POJ-1001 求高精度幂-大数乘法系列
- POJ-1003 Hangover
- POJ-1004 Financial Management
- 用单调栈解决最大连续矩形面积问题
- 线段树
- 2632 Crashing Robots的解决方法
- POJ——3253 Fence Repair