可持久化数据结构

1.trie的可持久化

2.线段树的可持久化——主席树

前提:本身的拓扑结构不变。(例如线段树的分块模型,左右块是不变化的,知识信息在变化)

解决什么样的问题:可以存下数据结构的所有历史版本。

核心思想:只记录每一个版本和前面一个版本的不同之处。

每一次修改不一样的节点,只会记录O(logn)个节点,将平方级别优化成了log级别。

最大异或和

可持久化trie

建立一个新的版本

儿子的信息是不一样的,直接裂开。

不一样的就建立一条新的边。一样的就直接往原来的图上面连接。

#include <bits/stdc++.h>
using namespace std;
const int N = 600002, M = N * 25;
int n, m, sum[N], rt[N], mxid[M], tr[M][2], idx = 0;
void insert(int x, int u, int v)
{
	mxid[u] = x;
	for (int k = 23; k >= 0; -- k)
	{
		int y = (sum[x] >> k) & 1;
		if(v) tr[u][y ^ 1] = tr[v][y ^ 1];
		tr[u][y] = ++ idx;
		u = tr[u][y], v = tr[v][y], mxid[u] = x;
	}
	return ;
}
int query(int u, int x, int L)
{
	int tot = 0;
	for (int k = 23; k >= 0; -- k)
	{
		int y = (x >> k) & 1;
		if(mxid[tr[u][y ^ 1]] >= L) u = tr[u][y ^ 1], tot += (1 << k);
		else u = tr[u][y];
	}
	return x ^ sum[mxid[u]];
}
int main()
{
	scanf("%d %d", &n, &m);
	mxid[0] = -1, rt[0] = ++ idx;
	insert(0, rt[0], 0);
	for (int i = 1; i <= n; ++ i) 
	{
		int x;
		scanf("%d", &x);
		sum[i] = sum[i - 1] ^ x, rt[i] = ++ idx;
		insert(i, rt[i], rt[i - 1]);
	}
	for (int i = 1; i <= m; ++ i)
	{
		char s[2]; int x, l, r;
		scanf("%s", s);
		if(*s == 'A')
		{
			scanf("%d", &x);
			n ++, sum[n] = sum[n - 1] ^ x, rt[n] = ++ idx;
			insert(n, rt[n], rt[n - 1]);	
		}
		else
		{
			scanf("%d %d %d", &l, &r, &x);
			printf("%d\n", query(rt[r - 1], sum[n] ^ x, l - 1));
		}
	}
	return 0;
}

第K小数

#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
struct segement_tree
{
	int l, r, cnt;
}tr[N * 21];
int idx = 0, rt[N], n, m, a[N], b[N], tot;
void push_up(int p) {tr[p].cnt = tr[tr[p].l].cnt + tr[tr[p].r].cnt; }
int build_tree(int l, int r)
{
	int p = ++ idx;
	if(l == r) return p;
	int mid = l + r >> 1;
	tr[p].l = build_tree(l, mid), tr[p].r = build_tree(mid + 1, r);
	return p; 
}
int insert(int p, int l, int r, int x)
{
	int q = ++ idx;
	tr[q] = tr[p];
	if(l == r) {tr[q].cnt ++; return q; }
	int mid = l + r >> 1;
	if(x <= mid) tr[q].l = insert(tr[p].l, l, mid, x);
	else tr[q].r = insert(tr[p].r, mid + 1, r, x);
	
	push_up(q);
	return q;
}
int query(int q, int p, int l, int r, int k)
{
	if(l == r) return l;
	int cnt = tr[tr[q].l].cnt - tr[tr[p].l].cnt;
	int mid = l + r >> 1;
	if(k <= cnt) return query(tr[q].l, tr[p].l, l, mid, k);
	else return query(tr[q].r, tr[p].r, mid + 1, r, k - cnt); 
}
int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]), b[i] = a[i];
	sort(b + 1, b + n + 1);
	tot = unique(b + 1, b + n +1) - b - 1;
	for (int i = 1; i <= n; ++ i) a[i] = lower_bound(b + 1, b + tot + 1, a[i]) - b;
	rt[0] = build_tree(1, tot);
	for (int i = 1; i <= n; ++ i)
	{
		rt[i] = insert(rt[i - 1], 1, tot, a[i]);
	}
	
	for (int i = 1; i <= m; ++ i)
	{
		int l, r, k;
		scanf("%d %d %d", &l, &r, &k);
		printf("%d\n", b[query(rt[r], rt[l - 1], 1, tot, k)]);
	}
	return 0;
}
posted @ 2025-02-13 10:39  Helioca  阅读(17)  评论(0)    收藏  举报
Document