可持久化线段树
这是个非常经典的主席树入门题——静态区间第 \(k\) 小。
对于指定的闭区间 \([l, r]\) 查询其区间内的第 \(k\) 小值.
代码采用指针形式,区间为左闭右闭。
const ll M = 2e5 + 3;
int n, N, m, tot, a[M], b[M];
struct node
{
int L, R, cnt;
node *lc, *rc;
};
struct node by[M * 21], *pool = by, *root[M];
node *New()
{
return ++pool;
}
void update(node *&now)
{
now->cnt = now->lc->cnt + now->rc->cnt;
}
node *build(int l, int r)
{
node *now = New();
now->L = l;
now->R = r;
if (l < r)
{
int mid = (l + r) >> 1;
now->lc = build(l, mid);
now->rc = build(mid + 1, r);
update(now);
}
else
{
now->cnt = 0;
now->lc = now->rc = NULL;
}
return now;
}
inline bool out(node *&now, int l, int r)
{
return (now->R < l) || (r < now->L);
}
void change(node *pre, node *now, int x)
{
*now = *pre;
if (pre->L == x and pre->R == x)
now->cnt++;
else
{
if (!out(pre->lc, x, x))
{
now->lc = New();
change(pre->lc, now->lc, x);
update(now);
}
else
{
now->rc = New();
change(pre->rc, now->rc, x);
update(now);
}
}
}
int check(node *&nowl, node *&nowr, int k)
{
if (nowl->L == nowl->R)
return nowl->L;
int lcnt = nowr->lc->cnt - nowl->lc->cnt;
if (lcnt >= k)
return check(nowl->lc, nowr->lc, k);
else
return check(nowl->rc, nowr->rc, k - lcnt);
}
void Main()
{
n = read();
m = read();
for (int i = 1; i <= n; ++i)
{
a[i] = read();
b[i] = a[i];
}
sort(b + 1, b + n + 1);
N = unique(b + 1, b + n + 1) - b - 1;
for (int i = 1; i <= n; ++i)
a[i] = lower_bound(b + 1, b + N + 1, a[i]) - b;
root[0] = build(1, N);
for (int i = 1; i <= n; ++i)
{
root[++tot] = New();
change(root[tot - 1], root[tot], a[i]);
}
for (int i = 1; i <= m; ++i)
{
int l, r, k;
l = read(), r = read(), k = read();
int ans = b[check(root[l - 1], root[r], k)];
printf("%d\n", ans);
}
}