P3834 [Template] Persistent segment tree 2

topic description

As in the title, given a sequence a composed of n integers, the kth smallest value in the specified closed interval [l,r] will be queried.

input format

The first line contains two integers, representing the length nn of the sequence and the number m of queries, respectively.
The second line contains n integers, the i-th integer representing the i-th element ai​ of the sequence.
Each of the next m lines contains three integers l, r, k representing the kth smallest value in the query interval [[l,r].

output format

For each query, output an integer on a line representing the answer.

Input and output samples

Type #1 to copy

5 5
25957 6405 15770 26287 26465 
2 2 1
3 4 1
4 5 1
1 2 2
4 4 1

output #1 copy

6405
15770
26287
25957
26287

Problem-solving ideas:

The persistent line segment tree is a simple extension of the basic line segment tree. It is characterized by supporting the query of historical versions, and using the shared data between historical versions to reduce time and space consumption.

The ideas it contains include prefixes and ideas, common points, discretization, weight line segment trees, and dynamic opening points.

When we record the weight line segment tree, it is impossible to open a brand new tree every time to record the value of its nodes.

This is to think of dynamic opening points, record the root node, and open up a new space for the changed node to record the value of it and its child nodes.

The idea of ​​using the prefix sum is that the difference between the value of the previously recorded long-term node and the value of the node opened later is how many nodes are newly added. The interval [L,R] contains elements equal to the interval [1,R] minus the interval [1,L-1].

Problem-solving code:

#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;
}

Guess you like

Origin blog.csdn.net/zhi6fui/article/details/128574206