可持久化字典树
可持久化字典树与可持久化线段树类似。
解决的问题都是类似于“有限制的前缀和”,或二维问题。
而可持久化字典树更多的是解决异或问题,即运用01字典树。
解决异或最大问题,贪心地在字典树上选择。
例题
用前缀异或和把最大的区间异或和转化成单点。
想要与 x 异或后最大,就从高到低 x 在二进制上的每一位,贪心的查找在这一位能不能取到与 x 相反的值。
查找:设合法的吗,与 x 异或值最大的数为ans。因为从高到低枚举每一位,所以 ans 的前缀已经知道,当前这一位加上后的ans′ 也可以求出。在字典树上查一下,如果有 以 ans′ 为前缀的数,那 ans′就是合法的。这里的查找实际上是检验贪心的取法会不会在后面出现问题。(取不到)
单点有 l,r 的限制,就用可持久化来解决。
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int MAXN=6e5+5;
int a[MAXN],s[MAXN];
int rt[MAXN];
int ch[MAXN*30][2],cnt[MAXN*30];
int tot;
void insert(int &u,int t,int x){//t:从右往左第t位
// printf("%d %d %d %d\n",u,t,x,id);
cnt[++tot]=cnt[u]+1;
if(t<0) {u=tot;return;}
ch[tot][0]=ch[u][0];
ch[tot][1]=ch[u][1];
u=tot;
int y=(x>>t)&1;
insert(ch[u][y],t-1,x);
}
int ask(int u,int v,int t,int x){
if(t<0) return 0;
int y=(x>>t)&1;
if(cnt[ch[v][!y]]>cnt[ch[u][!y]]) return (1<<t)+ask(ch[u][!y],ch[v][!y],t-1,x);
else return ask(ch[u][y],ch[v][y],t-1,x);
}
int main(){
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
scanf("%d%d",&n,&m);
insert(rt[0],25,0);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
s[i]=(s[i-1]^a[i]);
rt[i]=rt[i-1];
insert(rt[i],25,s[i]);
// printf("A\n");
}
insert(rt[0],25,0);
for(int i=1;i<=m;i++){
char op;
int l,r,x;
scanf("\n%c",&op);
if(op=='A'){
scanf("%d",&x);
n++;
s[n]=(s[n-1]^x);rt[n]=rt[n-1];
insert(rt[n],25,s[n]);
}else{
scanf("%d%d%d",&l,&r,&x);
l--,r--;
x^=s[n];
if(l==0) printf("%d\n",ask(0,rt[r],25,x));
else printf("%d\n",ask(rt[l-1],rt[r],25,x));
}
}
return 0;
}
这道题和模板题很像,但其实运用的只是字典树的思想。更重要的是这道题提供了一种新的01字典树的理解方式。
通常我们看字典树,一个节点表示的就是它到根节点所组成的数字/字符串。
但还有一种思路,一个节点,若它的前缀是 s,到叶子节点的距离为 x.那这个节点可以表示一个区间 [s,s+(1<<x)−1].
本文来自博客园,作者:bwartist,转载请注明原文链接:https://www.cnblogs.com/bwartist/p/17700640.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现