Loading

主席树【可持久化线段树】

\(OI\) 👴 \(hjt\) 发明的,所以叫主席树

可持久化线段树

所谓可持久化,其实就是保存了历史版本信息,类似前缀和的一种信息。

但是其实就是每次都进行单点修改,区间修改的话还没有见识过。

好像是有这样的题目,以后再学。

每次更新一条链,在动态开点的时候复制之前节点的信息,然后再继续开点

代码其实很好写

洛谷模板 区间k小

/*
 * @Author: zhl
 * @Date: 2020-10-12 19:34:06
 */

 
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i = a;i <= b;i++)
#define mid (l+r>>1)
using namespace std;

const int N = 5e5 + 10;


int L[N << 5], R[N << 5], sum[N << 5];
int tot;

int build(int l, int r) {
	int u = ++tot;
	sum[u] = 0;
	if (l < r) {
		L[u] = build(l, mid);
		R[u] = build(mid + 1, r);
	}
	return u;
}

int insert(int pre, int l, int r, int pos) {
	int u = ++tot;
	L[u] = L[pre];
	R[u] = R[pre];
	sum[u] = sum[pre] + 1;

	if (l >= r)return u;

	if (pos <= mid) {
		L[u] = insert(L[pre], l, mid, pos);
	}
	else {
		R[u] = insert(R[pre], mid + 1, r, pos);
	}
	return u;
}

int query(int rt_x, int rt_y, int l, int r, int k) {
	if (l == r) {
		return r;
	}
	int num = sum[L[rt_y]] - sum[L[rt_x]];//区间内,左半区间的数的数量
	if (num >= k) {
		//在左边
		return query(L[rt_x], L[rt_y], l, mid, k);
	}
	else {
		return query(R[rt_x], R[rt_y], mid + 1, r, k - num);
	}
}

int n, m;
int A[N], id[N], root[N];

int main() {
	cin >> n >> m;
	rep(i, 1, n) {
		cin >> A[i];
		id[i] = A[i];
	}
	sort(id + 1, id + 1 + n);
	int cntID = unique(id + 1, id + 1 + n) - id - 1;
	root[0] = build(1, cntID);

	rep(i, 1, n) {
		int pos = lower_bound(id + 1, id + 1 + cntID, A[i]) - id;
		root[i] = insert(root[i - 1], 1, cntID, pos);
	}

	rep(i, 1, m) {
		int x, y, k;
		cin >> x >> y >> k;
		int pos = query(root[x - 1], root[y], 1, cntID, k);
		cout << id[pos] << endl;
	}
}

洛谷模板 可持久化数组

搞一个主席树维护就可以

/*
 * @Author: zhl
 * @Date: 2020-10-13 09:13:50
 */
#include<bits/stdc++.h>
#define mid (l+r>>1)
using namespace std;

const int N = 5e5 + 10;
int L[N << 5], R[N << 5], sum[N << 5], tot;

int id[N], A[N], root[N];

int build(int l, int r) {
	int u = ++tot;
	if (l == r) {
		sum[u] = A[l];
		return u;
	}
	L[u] = build(l, mid);
	R[u] = build(mid + 1, r);
	sum[u] = sum[L[u]] + sum[R[u]];
	return u;
}

int updt(int v, int l, int r, int pos, int val) {
	int u = ++tot;
	L[u] = L[v];
	R[u] = R[v];

	if (l == r) {
		sum[u] = val;
		return u;
	}
	if (pos <= mid) {
		L[u] = updt(L[v], l, mid, pos, val);
		sum[u] = sum[L[u]] + sum[R[u]];
	}
	else {
		R[u] = updt(R[v], mid + 1, r, pos, val);
		sum[u] = sum[L[u]] + sum[R[u]];
	}
	return u;
}

int clone(int v, int l, int r, int pos) {
	int u = ++tot;
	L[u] = L[v];
	R[u] = R[v];
	sum[u] = sum[v];

	if (l >= r) {
		printf("%d\n", sum[v]);
		return u;
	}
	if (pos <= mid) clone(L[v], l, mid, pos);
	else clone(R[v], mid + 1, r, pos);
	return u;
}

int n, m;
int v, op, loc, val;
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%d", A + i);
	}
	root[0] = build(1, n);

	for (int i = 1; i <= m; i++) {
		scanf("%d%d", &v, &op);
		if (op == 1) {
			scanf("%d%d", &loc, &val);
			root[i] = updt(root[v], 1, n, loc, val);
		}
		else {
			scanf("%d", &loc);
			root[i] = clone(root[v], 1, n, loc);
		}
	}
}
posted @ 2020-10-13 16:04  —O0oO-  阅读(95)  评论(0编辑  收藏  举报