P3834 [テンプレート] 永続セグメントツリー 2

トピックの説明

タイトルのように、n 個の整数で構成されるシーケンス a が与えられると、指定された閉区間 [l,r] 内の k 番目に小さい値がクエリされます。

入力フォーマット

最初の行には、シーケンスの長さ nn とクエリの数 m をそれぞれ表す 2 つの整数が含まれています。
2 行目には n 個の整数が含まれており、i 番目の整数はシーケンスの i 番目の要素 ai を表します。
次の m 行のそれぞれには、クエリ間隔 [[l,r]] 内の k 番目に小さい値を表す 3 つの整数 l、r、k が含まれています。

出力フォーマット

クエリごとに、答えを表す整数を行に出力します。

入力サンプルと出力サンプル

#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