описание темы
Как и в заголовке, для последовательности a, состоящей из n целых чисел, будет запрошено k-е наименьшее значение в указанном замкнутом интервале [l,r].
формат ввода
Первая строка содержит два целых числа, представляющих длину последовательности nn и количество запросов m соответственно.
Вторая строка содержит n целых чисел, i-е целое число представляет i-й элемент ai последовательности.
Каждая из следующих m строк содержит три целых числа l, r, k, представляющие k-е наименьшее значение в интервале запроса [[l,r].
Выходной формат
Для каждого запроса выведите целое число в строке, представляющей ответ.
Входные и выходные образцы
Введите #1 , чтобы скопировать
5 5 25957 6405 15770 26287 26465 2 2 1 3 4 1 4 5 1 1 2 2 4 4 1
копия вывода №1
6405 15770 26287 25957 26287
Идеи решения проблем:
Постоянное дерево отрезков линий представляет собой простое расширение базового дерева отрезков линий. Оно характеризуется поддержкой запроса исторических версий и использованием общих данных между историческими версиями для сокращения затрат времени и пространства.
Содержащиеся в нем идеи включают префиксы и идеи, общие точки, дискретизацию, деревья сегментов весовых линий и динамические открывающиеся точки.
Когда мы записываем дерево отрезков весовых линий, невозможно каждый раз открывать новое дерево для записи значений его узлов.
Это значит подумать о динамических точках открытия, записать корневой узел и открыть новое пространство для измененного узла, чтобы записать значение его и его дочерних узлов.
Идея использования суммы префикса заключается в том, что разница между значением ранее записанного долгосрочного узла и значением узла, открытого позже, и есть количество новых добавленных узлов. Интервал [L,R] содержит элементы, равные интервалу [1,R] минус интервал [1,L-1].
Код решения проблемы:
#include<bits/stdc++.h>
using namespace std;
const int N = 200010;
int cnt = 0;
int a[N], b[N], root[N];
struct {
int L, R, sum;
}tree[N<<5];
int update(int pre, int pl, int pr, int x) {
int rt = ++cnt;
tree[rt].L = tree[pre].L;
tree[rt].R = tree[pre].R;
tree[rt].sum = tree[pre].sum + 1;
int mid = (pl + pr) >> 1;
if (pl < pr) {
if (x <= mid) {
tree[rt].L = update(tree[pre].L, pl, mid, x);
}
else {
tree[rt].R = update(tree[pre].R, mid + 1, pr, x);
}
}
return rt;
}
int query(int u, int v, int pl, int pr, int k) {
if (pl == pr) return pl;
int x = tree[tree[v].L].sum - tree[tree[u].L].sum;
int mid = (pr + pl) >> 1;
if (x >= k) {
return query(tree[u].L, tree[v].L, pl, mid, k);
}
else {
return query(tree[u].R, tree[v].R, mid + 1, pr, k - x);
}
}
int main() {
int n, m;
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);
int size = unique(b + 1, b + 1 + n) - b - 1; // 不重复的个数
for (int i = 1; i <= n; i++) {
int x = lower_bound(b + 1, b + 1 + size, a[i]) - b;
root[i] = update(root[i - 1], 1, size, x);
}
while (m--) {
int x, y, k;
cin >> x >> y >> k;
int t = query(root[x - 1], root[y], 1, size, k);
printf("%d\n", b[t]);
}
return 0;
}