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.

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.

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

时间: 2024-11-10 13:27:59

poj 2104:K-th Number(划分树,经典题)的相关文章

【POJ 2104】 K-th Number 主席树模板题

达神主席树讲解传送门:http://blog.csdn.net/dad3zz/article/details/50638026 2016-02-23:真的是模板题诶,主席树模板水过.今天新校网不好,没有评测,但我立下flag这个代码一定能A.我的同学在自习课上考语文,然而机房党都跑到机房来避难了\(^o^)/~ #include<cstdio> #include<cstring> #include<algorithm> #define for1(i,a,n) for(i

POJ2104 K-th Number 划分树 模板题啊

/*Source Code Problem: 2104 User: 96655 Memory: 14808K Time: 1282MS Language: G++ Result: Accepted Source Code*/ #include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #include<vector> #include<stack>

poj 2104 K-th Number(划分树模板)

划分树模板题,敲上模板就ok了. #include<algorithm> #include<iostream> #include<cstring> #include<vector> #include<cstdio> #include<cmath> #include<queue> #include<stack> #include<map> #include<set> #define MP

POJ 2761-Feed the dogs(划分树)求区间内第k小的数

Feed the dogs Time Limit: 6000MS   Memory Limit: 65536K Total Submissions: 17679   Accepted: 5561 Description Wind loves pretty dogs very much, and she has n pet dogs. So Jiajia has to feed the dogs every day for Wind. Jiajia loves Wind, but not the

poj 2182 Lost Cows(线段树经典题)

题目链接:http://poj.org/problem?id=2182 Lost Cows Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9152   Accepted: 5879 Description N (2 <= N <= 8,000) cows have unique brands in the range 1..N. In a spectacular display of poor judgment, th

[NBUT 1458 Teemo]区间第k大问题,划分树

裸的区间第k大问题,划分树搞起. #pragma comment(linker, "/STACK:10240000") #include <map> #include <set> #include <cmath> #include <ctime> #include <deque> #include <queue> #include <stack> #include <vector> #inc

划分树模板题

原题http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 37130   Accepted: 11974 Case Time Limit: 2000MS Description You are working for Macrohard company in data structures department. After failing

poj 2104 K-th Number(划分树)

题目链接:http://poj.org/problem?id=2104 题目分析:该问题给定一段区间中的值,再给定一段查询区间[ql, qr],需要给出该查询区间中的值在排序后的第K大的值: 使用划分树即可解决该问题:划分树的建树的复杂度为O(NlogN),查询一个区间的第K大值的复杂度为O(logN): 代码如下: #include <cstdio> #include <iostream> #include <algorithm> using namespace st

POJ 2104 区间第K大值(划分树做法)

由于深感自己水平低下,把大部分有效时间放在了刷题上,于是好久没写题解了.今天刚学了下划分树的原理,于是写道简单题练练手. 题目链接:http://poj.org/problem?id=2104 划分树的空间复杂度和时间复杂度均为O(nlogn),对于解决该问题而言,每次查询的复杂度为O(logn),比归并树O((log)^3)节省时间[归并树采用了三次二分]. 但是划分树也有自己的缺点,不支持更新以及适用范围狭窄,总之...是时代的眼泪了= = AC代码: #include <iostream>

poj 2104 K-th Number (划分树入门)

题意:给n个数,m次询问,每次询问L到R中第k小的数是哪个 算法:划分树 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 using namespace std; 6 7 const int mx=1e5+5; 8 int tree[30][mx]; 9 int sortt[mx]; 10 int sum[30][mx]; 11 12 vo