可持久化数据结构

好多细节啊,细节能不能爬出 OI。

可持久化线段树

做相关题目的时候注意一下空间。设一个线段树存储的值域为 n,则每新建一棵线段树都至多创建 logn+1 个节点。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mid (l + r >> 1)
#define lowbit(x) (x & -x)

const int N = 1e6 + 5, M = 2e7 + 3e6 + 5;

int n, m, lst, opt, k, x;
int val[N], rt[N];

struct Segment_Tree {
	int cnt = 1;
	struct Node { int l, r, val; } a[M];
	
	void build(int p, int l, int r) {
		if (l == r) { a[p].val = val[l]; return ; }
		a[p].l = ++cnt; build(cnt, l, mid);
		a[p].r = ++cnt; build(cnt, mid + 1, r);
	}
	
	int update(int p, int l, int r, int k, int val) {
		a[++cnt] = a[p]; p = cnt;
		if (l == r) { a[p].val = val; return p; }
		if (k <= mid) a[p].l = update(a[p].l, l, mid, k, val);
		else a[p].r = update(a[p].r, mid + 1, r, k, val);
		return p;
	}
	
	int query(int p, int l, int r, int k) {
		if (l == r) return a[p].val;
		if (k <= mid) return query(a[p].l, l, mid, k);
		else return query(a[p].r, mid + 1, r, k);
	}
} ST;

signed main() {
	cin >> n >> m;
	for (int i = 1; i <= n; ++i) scanf("%d", &val[i]);
	rt[0] = 1; ST.build(1, 1, n);
	for (int i = 1; i <= m; ++i) {
		scanf("%d%d", &lst, &opt);
		if (opt == 1) { scanf("%d%d", &k, &x); rt[i] = ST.update(rt[lst], 1, n, k, x); }
		else { scanf("%d", &k); rt[i] = rt[lst]; printf("%d\n", ST.query(rt[i], 1, n, k)); }
	}
	return 0;
}
  • P3834 【模板】可持久化线段树 2

    可持久化线段树模板题。

    思路是建立可持久化值域线段树。对于第 i 个数,都记一个 rti 存储 a1,...,ai 对应的值域线段树的根。同样也注意一下空间。

    非离散化版本:

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mid (l + r >> 1)
#define lowbit(x) (x & -x)

const int N = 2e5 + 5, M = 6e6 + 2e5 + 5;

int n, m, l, r, k;
int val[N], rt[N];

struct Segment_Tree {
	int cnt = 1;
	struct Node { int l, r, sum; } a[M];
	
	void push_up(int p) {
		a[p].sum = a[a[p].l].sum + a[a[p].r].sum;
	}
	
	int update(int p, int l, int r, int k) {
		a[++cnt] = a[p]; p = cnt;
		if (l == r) { ++a[p].sum; return p; }
		if (k <= mid) a[p].l = update(a[p].l, l, mid, k);
		else a[p].r = update(a[p].r, mid + 1, r, k);
		push_up(p); return p;
	}
	
	int query(int pl, int pr, int l, int r, int k) {
		if (l == r) return l;
		if (a[a[pr].l].sum - a[a[pl].l].sum >= k) return query(a[pl].l, a[pr].l, l, mid, k);
		return query(a[pl].r, a[pr].r, mid + 1, r, k - (a[a[pr].l].sum - a[a[pl].l].sum));
	}
} ST;

signed main() {
	cin >> n >> m;
	for (int i = 1; i <= n; ++i) { cin >> val[i]; rt[i] = ST.update(rt[i - 1], 0, 1e9, val[i]); }
	while (m--) {
		cin >> l >> r >> k;
		cout << ST.query(rt[l - 1], rt[r], 0, 1e9, k) << endl;
	}
	return 0;
}

离散化版本:

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mid (l + r >> 1)
#define lowbit(x) (x & -x)

const int N = 2e5 + 5, M = 4e6 + 5;

int n, m, l, r, k;
int p[N], val[N], rt[N];

void lsh(int a[], int n) {
	vector<int> v;
	for (int i = 1; i <= n; ++i) v.push_back(a[i]);
	sort(v.begin(), v.end());
	v.erase(unique(v.begin(), v.end()), v.end());
	for (int i = 1; i <= n; ++i) {
		int res = lower_bound(v.begin(), v.end(), a[i]) - v.begin() + 1;
		p[res] = a[i]; a[i] = res;
	}
}

struct Segment_Tree {
	int cnt = 1;
	struct Node { int l, r, sum; } a[M];
	
	void push_up(int p) {
		a[p].sum = a[a[p].l].sum + a[a[p].r].sum;
	}
	
	int update(int p, int l, int r, int k) {
		a[++cnt] = a[p]; p = cnt;
		if (l == r) { ++a[p].sum; return p; }
		if (k <= mid) a[p].l = update(a[p].l, l, mid, k);
		else a[p].r = update(a[p].r, mid + 1, r, k);
		push_up(p); return p;
	}
	
	int query(int pl, int pr, int l, int r, int k) {
		if (l == r) return l;
		if (a[a[pr].l].sum - a[a[pl].l].sum >= k) return query(a[pl].l, a[pr].l, l, mid, k);
		return query(a[pl].r, a[pr].r, mid + 1, r, k - (a[a[pr].l].sum - a[a[pl].l].sum));
	}
} ST;

signed main() {
	cin >> n >> m;
	for (int i = 1; i <= n; ++i) cin >> val[i];
	lsh(val, n);
	for (int i = 1; i <= n; ++i) rt[i] = ST.update(rt[i - 1], 1, n, val[i]);
	while (m--) {
		cin >> l >> r >> k;
		cout << p[ST.query(rt[l - 1], rt[r], 1, n, k)] << endl;
	}
	return 0;
}
posted @   zyb_txdy  阅读(5)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示