主席树启蒙题——静态区间第k小值

题意:

第一行两个正整数N,M。

第二行N个数,表示序列A1,A2,...,AN。

紧着的M行,每行三个正整数i,j,k(k≤j-i+1),表示 询问Ai...Aj中第k小的数等于多少。

解法:主席树。

先离散,然后对于每一个前缀开一棵权值线段树Ri,用来计算在A1..Ai的区间内某个数的名次。

然后线段树是可以对应点相减的,即Rj-R(i-1)可以计算Ai..Aj的区间内某个数的名次。

线段树上二分即可。

 1 #include <algorithm>
 2 #include <stdio.h>
 3 #include <utility>
 4 const int N = 100001;
 5 
 6 typedef struct Node *Tree;
 7 struct Node {
 8     int l, r, size;
 9     Tree ch[2];
10 } nodes[N * 20], *now = nodes, *root[N];
11 void build(Tree &tr, register int l, register int r) {
12     tr = now++;
13     tr->l = l;
14     tr->r = r;
15     tr->size = 0;
16     if(l == r) tr->ch[0] = tr->ch[1] = 0;
17     else build(tr->ch[0], l, l + r >> 1), build(tr->ch[1], l + r + 2 >> 1, r);
18 }
19 void insert(Tree &tr, int pos) {
20     *now = *tr;
21     tr = now++;
22     ++tr->size;
23     if(tr->l != tr->r) insert(tr->ch[pos >= tr->ch[1]->l], pos);
24 }
25 int query(Tree pre, Tree end, register int k) {
26     if(pre->l == pre->r) return pre->l;
27     register int s = end->ch[0]->size - pre->ch[0]->size;
28     if(k <= s) return query(pre->ch[0], end->ch[0], k);
29     else return query(pre->ch[1], end->ch[1], k - s);
30 }
31 
32 std::pair<int, int> a[N];
33 int n, m, no[N];
34 int main() {
35     scanf("%d%d", &n, &m);
36     for(int i = 1; i <= n; ++i) {
37         scanf("%d", &a[i].first);
38         a[i].second = i;
39     }
40     std::sort(a + 1, a + n + 1);
41     for(int i = 1; i <= n; ++i) {
42         no[a[i].second] = i;
43     }
44     build(root[0], 1, n);
45     for(int i = 1; i <= n; ++i) {
46         root[i] = root[i - 1];
47         insert(root[i], no[i]);
48     }
49     while(m--) {
50         int i, j, k;
51         scanf("%d%d%d", &i, &j, &k);
52         printf("%d\n", a[query(root[i - 1], root[j], k)].first);
53     }
54     return 0;
55 }
View Code

转载于:https://www.cnblogs.com/nealchen/p/5538340.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值