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
#include
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]之间出现的。
*/