ACM模版
描述
题解
遇见这种题,果断直接套模版,主席树,也就是可持久化线段树。
这里需要说一下,由于比较懒,我的模版求得是第 K 小,并且下标是从
0∼n
,所以呢,我直接在输出时下标偏移了一,并且对
k
稍加修饰,变成了求第 r−l 2−k 小的数,效果是一模一样的,就酱紫。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN =
1e5;
const int MAXM = MAXN *
30;
int n, q, m, tot;
int a[MAXN], t[MAXN];
int T[MAXN], lson[MAXM], rson[MAXM], c[MAXM];
void Init_hash()
{
for (
int i =
1; i <= n; i++)
{
t[i] = a[i];
}
sort(t +
1, t +
1 + n);
m = (
int)(unique(t +
1, t +
1 + n) - t -
1);
}
int build(
int l,
int r)
{
int root = tot++; c[root] =
0;
if (l != r)
{
int mid = (l + r) >>
1;
lson[root] = build(l, mid);
rson[root] = build(mid +
1, r);
}
return root;
}
int hash_(
int x)
{
return (
int)(lower_bound(t +
1, t +
1 + m, x) - t);
}
int update(
int root,
int pos,
int val)
{
int newroot = tot++, tmp = newroot;
c[newroot] = c[root] + val;
int l =
1, r = m;
while (l < r)
{
int mid = (l + r) >>
1;
if (pos <= mid)
{
lson[newroot] = tot++;
rson[newroot] = rson[root];
newroot = lson[newroot];
root = lson[root];
r = mid;
}
else
{
rson[newroot] = tot++;
lson[newroot] = lson[root];
newroot = rson[newroot];
root = rson[root];
l = mid +
1;
}
c[newroot] = c[root] + val;
}
return tmp;
}
int query(
int left_root,
int right_root,
int k)
{
int l =
1, r = m;
while ( l < r)
{
int mid = (l + r) >>
1;
if (c[lson[left_root]] - c[lson[right_root]] >= k )
{
r = mid;
left_root = lson[left_root];
right_root = lson[right_root];
}
else
{
l = mid +
1;
k -= c[lson[left_root]] - c[lson[right_root]];
left_root = rson[left_root];
right_root = rson[right_root];
}
}
return l;
}
int main()
{
while (
scanf(
"%d", &n) ==
1)
{
tot =
0;
for (
int i =
1; i <= n; i++)
{
scanf(
"%d", &a[i]);
}
Init_hash();
T[n +
1] = build(
1, m);
for (
int i = n; i; i--)
{
int pos = hash_(a[i]);
T[i] = update(T[i +
1], pos,
1);
}
scanf(
"%d", &q);
int l, r, k;
while (q--)
{
scanf(
"%d%d%d", &l, &r, &k);
printf(
"%d\n", t[query(T[l +
1], T[r +
2], r - l +
2 - k)]);
}
}
return 0;
}
参考
《主席树》