P3834 [Шаблон] Постоянное дерево сегментов 2

описание темы

Как и в заголовке, для последовательности 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;
}

рекомендация

отblog.csdn.net/zhi6fui/article/details/128574206