可持久化数据结构

可持久化线段树

这个

可持久化字典树

最大异或和

考虑设 \(s\)\(a\) 的前缀异或和数组,我们最终的答案就是找一个 \(p\in[l-1,r-1]\),然后求出 \(s_n\operatorname{xor} x\operatorname{xor} s_p\)

首先,对于最大异或数对问题,可以使用 \(01\) \(trie\) 解决,这里不再赘述。

类似于可持久化线段树,我们查询版本 \([l,r]\) 就是对前 \(r\) 个版本与前 \(l-1\) 个版本做差得到的,于是我们对于每个版本,先继承上一个版本,然后插入这个数。

然后我们每次修改就是开启一个新版本然后插入一个数,查询直接按照查询最大异或数对的方式对 \(s_n\operatorname{xor} x\) 进行查询即可。

代码:

#include<bits/stdc++.h>
#define int long long
#define N 600005
#define K 31
using namespace std;
int n,q,a[N],s[N];
struct trie{
	int rt[N],tr[N*K][2],val[N*K],idx;
	void ins(int las,int p,int v){
		for(int i=K-1;~i;i--){
			val[p]=val[las]+1;
			int t=v>>i&1;
			tr[p][t]=++idx;
			tr[p][!t]=tr[las][!t];
			p=tr[p][t];
			las=tr[las][t];
		}
		val[p]=val[las]+1;
	}
	int qry(int p,int q,int v){
		int res=0;
		for(int i=K-1;~i;i--){
			int t=v>>i&1;
			if(val[tr[q][!t]]-val[tr[p][!t]]){
				res+=1<<i;
				p=tr[p][!t];
				q=tr[q][!t];
			}
			else{
				p=tr[p][t];
				q=tr[q][t];
			}
		}
		return res;
	}
}trie;
signed main(){
	cin>>n>>q;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		s[i]=s[i-1]^a[i];
	}
	for(int i=1;i<=n;i++){
		trie.rt[i]=++trie.idx;
		trie.ins(trie.rt[i-1],trie.rt[i],s[i]);
	}
	while(q--){
		char op;
		int l,r,x;
		cin>>op;
		if(op=='A'){
			cin>>a[++n];
			s[n]=s[n-1]^a[n];
			trie.rt[n]=++trie.idx;
			trie.ins(trie.rt[n-1],trie.rt[n],s[n]);
		}
		else{
			cin>>l>>r>>x;
			l--;r--;
			if(l==0)cout<<max(s[n]^x,trie.qry(trie.rt[0],trie.rt[r],s[n]^x))<<'\n';
			else cout<<trie.qry(trie.rt[l-1],trie.rt[r],s[n]^x)<<'\n';
		}
	}
	return 0;
}

可持久化平衡树

鸽。

posted @ 2024-09-11 08:30  zxh923  阅读(1)  评论(0编辑  收藏  举报