P3834 [Plantilla] Árbol de segmento persistente 2

Tema Descripción

Como en el título, dada una secuencia a compuesta de n enteros, se consultará el k-ésimo valor más pequeño en el intervalo cerrado especificado [l,r].

formato de entrada

La primera línea contiene dos números enteros, que representan la longitud nn de la secuencia y el número m de consultas, respectivamente.
La segunda línea contiene n números enteros, el i-ésimo entero representa el i-ésimo elemento ai​ de la secuencia.
Cada una de las siguientes m líneas contiene tres números enteros l, r, k que representan el k-ésimo valor más pequeño en el intervalo de consulta [[l,r].

formato de salida

Para cada consulta, genere un número entero en una línea que represente la respuesta.

Muestras de entrada y salida

Escriba #1 para copiar

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

salida #1 copia

6405 
15770 
26287 
25957 
26287

Ideas para resolver problemas:

El árbol de segmentos de línea persistente es una extensión simple del árbol de segmentos de línea básico, se caracteriza por admitir la consulta de versiones históricas y utilizar datos compartidos entre versiones históricas para reducir el consumo de tiempo y espacio.

Las ideas que contiene incluyen prefijos e ideas, puntos comunes, discretización, árboles de segmentos de línea de peso y puntos de apertura dinámicos.

Cuando registramos el árbol de segmentos de línea de peso, es imposible abrir un árbol nuevo cada vez para registrar el valor de sus nodos.

Esto es pensar en puntos de apertura dinámicos, registrar el nodo raíz y abrir un nuevo espacio para que el nodo modificado registre su valor y el de sus nodos secundarios.

La idea de utilizar la suma del prefijo es que la diferencia entre el valor del nodo a largo plazo registrado previamente y el valor del nodo abierto más tarde es cuántos nodos se agregan recientemente. El intervalo [L,R] contiene elementos iguales al intervalo [1,R] menos el intervalo [1,L-1].

Código de resolución de problemas:

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

Supongo que te gusta

Origin blog.csdn.net/zhi6fui/article/details/128574206
Recomendado
Clasificación