Poj 2104区间第k大(归并树)

题目链接

K-th Number

Time Limit: 20000MS Memory Limit: 65536K
Total Submissions: 36890 Accepted: 11860
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.

题意很简单,给定长度为n的数组,有m次查询,每次长须L到R中第k大的数。

很早便想A掉这道题,开始用平方分割写的这题,妥妥的TLE. 后来知道这类题目应该

使用归并树,或者划分树,或是更高级的主席树,刚刚对归并树有一点了解,便来1A了他。

做法就是:如果x是某个区间的第k大数,那么区间内不超过x的数不小于k个。

而且区间内小于x的数不足k个。

二分x, 查询区间内不大于x的数的个数。

Accepted Code:

 1 /*************************************************************************
 2     > File Name: 2104.cpp
 3     > Author: Stomach_ache
 4     > Mail: [email protected]
 5     > Created Time: 2014年08月02日 星期六 19时25分26秒
 6     > Propose:
 7  ************************************************************************/
 8
 9 #include <cmath>
10 #include <string>
11 #include <cstdio>
12 #include <vector>
13 #include <fstream>
14 #include <cstring>
15 #include <iostream>
16 #include <algorithm>
17 using namespace std;
18
19 #define lson(x) (x<<1)
20 #define rson(x) ((x<<1)|1)
21 const int maxn = 100002;
22 int n, m;
23 int a[maxn], nums[maxn];
24 vector<int> dat[maxn<<2];
25
26 void build(int o, int l, int r) {
27       if (r - l == 1) {
28           dat[o].push_back(a[l]);
29     } else {
30           int mid = (l + r) / 2;
31           build(lson(o), l, mid);
32         build(rson(o), mid, r);
33         dat[o].resize(r-l);
34         merge(dat[lson(o)].begin(), dat[lson(o)].end(), dat[rson(o)].begin(), dat[rson(o)].end(), dat[o].begin());
35     }
36 }
37
38 int query(int L, int R, int x, int o, int l, int r) {
39       if (l >= R || r <= L) return 0;
40     else if (l >= L && r <= R) return upper_bound(dat[o].begin(), dat[o].end(), x) - dat[o].begin();
41     else {
42           int md = (l + r) / 2;
43           int lc = query(L, R, x, lson(o), l, md);
44         int rc = query(L, R, x, rson(o), md, r);
45         return lc + rc;
46     }
47 }
48
49 int main(void) {
50       while (~scanf("%d %d", &n, &m)) {
51           for (int i = 0; i < n; i++) scanf("%d", a + i);
52         build(1, 0, n);
53         sort(a, a + n);
54         while (m--) {
55               int l, r, k;
56             scanf("%d %d %d", &l, &r, &k);
57             l--; r--;
58             int lb = -1, ub = n-1;
59             while (ub - lb > 1) {
60                   int md = (lb + ub) / 2;
61                 int c = query(l, r+1, a[md], 1, 0, n);
62                 if (c >= k) ub = md;
63                 else lb = md;
64             }
65             printf("%d\n", a[ub]);
66         }
67     }
68
69     return 0;
70 }

Poj 2104区间第k大(归并树),布布扣,bubuko.com

时间: 2025-01-03 08:34:49

Poj 2104区间第k大(归并树)的相关文章

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

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

zoj2112 Dynamic Rankings 动态区间第k大,树状数组套平衡树

#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int

POJ 2014.K-th Number 区间第k大 (归并树)

K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 57543   Accepted: 19893 Case Time Limit: 2000MS Description You are working for Macrohard company in data structures department. After failing your previous task about key inse

【POJ】【2104】区间第K大

可持久化线段树 可持久化线段树是一种神奇的数据结构,它跟我们原来常用的线段树不同,它每次更新是不更改原来数据的,而是新开节点,维护它的历史版本,实现“可持久化”.(当然视情况也会有需要修改的时候) 可持久化线段树的应用有很多,仅以区间第K大这种简单的问题来介绍这种数据结构. 我们原本建立的线段树是表示区间的,或者说,维护的是[位置],存的是每个位置上的各种信息.它的优点是满足区间加法,但不满足区间减法,所以我们这里要换一种建树方式:对于每个区间[1,i]建立一棵权值线段树.这个线段树的作用其实就

poj 2401 划分树 求区间第k大的数

题目:http://poj.org/problem?id=2104 划分树待我好好理解下再写个教程吧,觉得网上的内容一般,,, 模板题: 贴代码: #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define CLR(a) memset(a,0,sizeof(a)) const int MAXN = 1000

POJ 2104 求序列里第K大 主席树裸体题

给定一个n的序列,有m个询问 每次询问求l-r 里面第k大的数字是什么 只有询问,没有修改 可以用归并树和划分树(我都没学过..囧) 我是专门冲着弄主席树来的 对主席树的建树方式有点了解了,不过这题为什么是在主席树里面这么操作的 还是有点不懂,今天照着模板敲了一遍就打多校了 再研究吧 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using name

POJ 2104 静态找区间第k大

静态区间第k大的问题,往往可以利用主席树来解决 这是主席树的第一道题 主席树大概可以理解为在n个节点上都建立一棵线段树,但是想想会超出内存 每一个节点保存的线段树都记录当前整段前缀区间的信息 但是因为每次添加后一个节点,那么他除了当前节点位置需要更新之外,其他的位置都可以保持跟上一棵节点对应的线段树一致,那么为了缩小内存, 将那些不需要改变的点的指针指向上一棵树对应的节点即可,其他多生成的节点也就是需要更新的节点,最多不超过log2n个,所以最后产生的线段树的 点的个数大概在nlogn的大致范围

poj2104 求区间第k大 可持久化线段树

poj2104 求区间第k大  可持久化线段树 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef

POJ2104-- K-th Number(主席树静态区间第k大)

[转载]一篇还算可以的文章,关于可持久化线段树http://finaltheory.info/?p=249 无修改的区间第K大 我们先考虑简化的问题:我们要询问整个区间内的第K大.这样我们对值域建线段树,每个节点记录这个区间所包含的元素个数,建树和查询时的区间范围用递归参数传递,然后用二叉查找树的询问方式即可:即如果左边元素个数sum>=K,递归查找左子树第K大,否则递归查找右子树第K – sum大,直到返回叶子的值. 现在我们要回答对于区间[l, r]的第K大询问.如果我们能够得到一个插入原序