首页 > 代码库 > Poj 2104区间第k大(归并树)

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

题目链接

K-th Number
Time Limit: 20000MSMemory Limit: 65536K
Total Submissions: 36890Accepted: 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 31 5 2 6 3 7 42 5 34 4 11 7 3

Sample Output

563

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: sudaweitong@gmail.com 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 }