HDU-2665 Kth number (主席树 不带修改区间第k大)

来源:互联网 发布:互联网大数据论文题目 编辑:程序博客网 时间:2024/06/05 11:55

Kth number

Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 13269    Accepted Submission(s): 4028


Problem Description
Give you a sequence and ask you the kth big number of a inteval.
 

Input
The first line is the number of the test cases. 
For each test case, the first line contain two integer n and m (n, m <= 100000), indicates the number of integers in the sequence and the number of the quaere. 
The second line contains n integers, describe the sequence. 
Each of following m lines contains three integers s, t, k. 
[s, t] indicates the interval and k indicates the kth big number in interval [s, t]
 

Output
For each test case, output m lines. Each line contains the kth big number.
 

Sample Input
1 10 1 1 4 2 3 5 6 7 8 9 0 1 3 2
 

Sample Output
2


#include <bits/stdc++.h>  using namespace std;    const int maxn = 100010;  const int INF = 1 << 30;int a[maxn], b[maxn], rt[maxn], tot;struct tree{int sum, lson, rson;}c[maxn << 5];int newNode(int sum, int lson, int rson){int id = ++tot;c[id].sum = sum;c[id].lson = lson;c[id].rson = rson;return id;}void insert(int& rt, int pre, int pos, int l, int r){rt = newNode(c[pre].sum + 1, c[pre].lson, c[pre].rson);if(l == r) return;int mid = l + r >> 1;if(pos <= mid) insert(c[rt].lson, c[pre].lson, pos, l, mid);else insert(c[rt].rson, c[pre].rson, pos, mid + 1, r);}int query(int Lrt, int Rrt, int l, int r, int k){if(l == r) return l;int mid = l + r >> 1;int sum = c[c[Rrt].lson].sum - c[c[Lrt].lson].sum;if(k <= sum) return query(c[Lrt].lson, c[Rrt].lson, l, mid, k);else return query(c[Lrt].rson, c[Rrt].rson, mid + 1, r, k - sum);}int main(){int T;scanf("%d", &T);while(T--){int n, m, l, r, k, pos, num;tot = rt[0] = 0;scanf("%d %d", &n, &m);for(int i = 1; i <= n; ++i){scanf("%d", &a[i]);b[i] = a[i];}sort(b + 1, b + 1 + n);num = unique(b + 1, b + 1 + n) - b - 1;for(int i = 1; i <= n; ++i){pos = lower_bound(b + 1, b + num + 1, a[i]) - b;insert(rt[i], rt[i - 1], pos, 1, num);}while(m--){scanf("%d %d %d", &l, &r, &k);pos = query(rt[l - 1], rt[r], 1, num, k);printf("%d\n", b[pos]);}}}      /*题意:1e5个数,1e5次询问,每次询问区间第k大。思路:将1e5个数离散化后映射到值域线段树上,这样线段树可以类似于平衡树,对于单次询问我们可以通过左右儿子的sz大小来找第k大的标号。对于多次询问我们需要用到主席树,记录历史的某个时刻线段树上的sz。我们按照数字出现的顺序建n棵线段树,对于没有修改到的结点,我们直接连到上一棵的结点,对于修改到的,我们开辟新结点。这样对于区间[L,R],我们只需要看第L-1棵和第R棵线段树上的sz来求第k大的标号即可。第L-1棵记录的是L之前出现的数字,减掉后就是在[L,R]之间出现的。*/


阅读全文
0 0
原创粉丝点击