可持久化 trie 的简单入门

可持久化 $trie$  ....又是一个表里不一的东西.....

可持久化 $trie$  的介绍:

和主席树类似的,其实可持久化就是体现在前缀信息的维护上(搞不懂这怎么就叫做可持久化了...)

$trie$ (字典树)大家应该都知道,就是一棵用来做字符串匹配的树,

但是!在这里,可持久化 $trie$ 就是完全不一样的东西了...

基本上(我做过的题),可持久化都是用来维护  $XOR$   信息的...

比如说求某个范围内的最大区间异或和之类的,至于到了树上嘛,你懂的.


可持久化 $trie$  的实现:

还是和主席树类似的,可持久化 $trie$   就是要你在一棵树上(由于是异或,数字都会变成二进制,值只有 0 和 1 两种表示,于是这棵树自然就是二叉树了)维护每个前缀出现的次数(这里就是类似 trie 的做法)

哎...相信你是没有看懂的...于是边看代码边自己感性理解一下吧....


可持久化 $trie$ 的代码实现:

这其实是一道板子题的代码...

 1 //by Judge
 2 #include<iostream>
 3 #include<cstdio>
 4 using namespace std;
 5 const int M=3e7+111;
 6 inline int read(){
 7     int x=0,f=1; char c=getchar();
 8     for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1;
 9     for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘; return x*f;
10 }
11 inline int cread(){
12     char c=getchar(); while(c!=‘Q‘ && c!=‘A‘) c=getchar(); return c^‘Q‘;
13 }
14 int n,m,cnt;
15 int rt[M],son[M][2],d[30],sum[M];
16 inline void split(int k){
17     int i,len=0;
18     while(k) d[++len]=k&1,k>>=1;
19     for(int i=len+1;i<=27;++i) d[i]=0;
20 }
21 inline void update(int& now,int las){
22     sum[now=++cnt]=sum[las]+1;
23     int i,tmp=now;
24     for(i=27;i;--i){
25         son[tmp][d[i]^1]=son[las][d[i]^1],
26         son[tmp][d[i]]=++cnt,las=son[las][d[i]],
27         sum[tmp=cnt]=sum[las]+1;
28     }
29 }
30 inline int query(int u,int v){
31     int ans=0,i;
32     for(i=27;i;--i){
33         if(sum[son[v][d[i]^1]]-sum[son[u][d[i]^1]]>0)
34             ans|=(1<<i-1),u=son[u][d[i]^1],v=son[v][d[i]^1];
35         else u=son[u][d[i]],v=son[v][d[i]];
36     } return ans;
37 }
38 int main(){
39     int sum=0,x,opt,l,r;
40     n=read(),m=read(),++n;
41     split(0),update(rt[1],rt[0]);
42     for(int i=2;i<=n;++i)
43         split(sum^=x=read()),
44         update(rt[i],rt[i-1]);
45     for(int i=1;i<=m;++i){
46         opt=cread();
47         if(opt)
48             split(sum^=x=read()),
49             update(rt[n+1],rt[n]),++n;
50         else
51             l=read(),r=read(),x=read(),split(x^sum),
52             printf("%d\n",query(rt[l-1],rt[r]));
53     } return 0;
54 }

view code

可持久化 $trie$  的例题:

其实上面已经是一道了。

这道题貌似满基础的(但我没做过,下次填坑): Alo

然后这道(树上搞事情)的题:Tree

代码如下:

 1 //by Judge
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 using namespace std;
 6 const int M=1e5+111;
 7 inline int read(){
 8     int x=0,f=1; char c=getchar();
 9     for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1;
10     for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘; return x*f;
11 }
12 int n,m,pat,cnt;
13 int head[M],d[20],rt[M],to[M<<5][2],sum[M<<5];
14 int val[M],siz[M],dep[M],top[M],f[M],son[M];
15 struct Edge{
16     int to,next;
17     Edge(int to,int next): to(to),next(next){} Edge(){}
18 }e[M<<1];
19 inline void add(int u,int v){
20     e[++pat]=Edge(v,head[u]),head[u]=pat;
21     e[++pat]=Edge(u,head[v]),head[v]=pat;
22 }
23 /*************         模板         ********************/
24 inline void split(int k){
25     int len=0,i;
26     while(k) d[++len]=k&1,k>>=1;
27     for(i=len+1;i<=18;++i) d[i]=0;
28 }
29 inline void update(int& root,int las){
30     int now=root=++cnt;
31     sum[now]=sum[las]+1;
32     for(int i=18;i;--i){
33         to[now][d[i]^1]=to[las][d[i]^1],
34         to[now][d[i]]=++cnt,las=to[las][d[i]],
35         now=cnt,sum[now]=sum[las]+1;
36     }
37 }
38 #define v e[i].to
39 void dfs1(int u,int fa){
40     siz[u]=1,son[u]=top[u]=0;
41     split(val[u]),update(rt[u],rt[fa]);
42     for(int i=head[u];i;i=e[i].next) if(v!=fa){
43         f[v]=u,dep[v]=dep[u]+1,dfs1(v,u),siz[u]+=siz[v];
44         if(siz[v]>siz[son[u]]) son[u]=v;
45     }
46 }
47 void dfs2(int u){
48     if(!top[u]) top[u]=u; if(!son[u]) return ;
49     top[son[u]]=top[u],dfs2(son[u]);
50     for(int i=head[u];i;i=e[i].next)
51         if(v!=son[u] && v!=f[u]) dfs2(v);
52 }
53 #undef v
54 inline int LCA(int u,int v){
55     while(top[u]^top[v])
56         dep[top[u]]>dep[top[v]]?u=f[top[u]]:v=f[top[v]];
57     return dep[u]<dep[v]?u:v;
58 }
59 /*          程序         */
60 inline int query(int u,int v,int lca,int f_lca){
61     int ans=0;
62     for(int i=18;i;--i){
63         if(sum[to[u][d[i]^1]]+sum[to[v][d[i]^1]]-sum[to[lca][d[i]^1]]-sum[to[f_lca][d[i]^1]])
64             ans|=(1<<i-1),u=to[u][d[i]^1],v=to[v][d[i]^1],lca=to[lca][d[i]^1],f_lca=to[f_lca][d[i]^1];
65         else u=to[u][d[i]],v=to[v][d[i]],lca=to[lca][d[i]],f_lca=to[f_lca][d[i]];
66     } return ans;
67 }
68 int x,y,z,lca;
69 inline void query(){
70     x=read(),y=read(),z=read(),lca=LCA(x,y),split(z);
71     printf("%d\n",query(rt[x],rt[y],rt[lca],rt[f[lca]]));
72 }
73 int main(){
74     while(~scanf("%d%d",&n,&m)){
75         pat=cnt=0,memset(head,0,sizeof(head));
76         for(int i=1;i<=n;++i) val[i]=read();
77         for(int i=1,u,v;i<n;++i)
78             u=read(),v=read(),add(u,v);
79         dfs1(1,0),dfs2(1); while(m--) query();
80     } return 0;
81 }

然后就是这题(TM做了我一晚上就在那里 TLE、 MLE 、WA  各种挂): L

代码如下:

 1 //by Judge
 2 #include<cmath>
 3 #include<cstdio>
 4 #include<iostream>
 5 #define ll long long
 6 using namespace std;
 7 const int M=12111;
 8 char buf[1<<20],*p1,*p2;
 9 #define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
10 inline int read(){
11     int x=0,f=1; char c=getchar();
12     for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1;
13     for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘; return x*f;
14 }
15 char sr[1<<21],z[20];int C=-1,Z;
16 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
17 inline void print(ll x){
18     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
19     while(z[++Z]=x%10+48,x/=10);
20     while(sr[++C]=z[Z],--Z);sr[++C]=‘\n‘;
21 }
22 int n,m,block,cnt,a[M<<1],f[311][M];
23 int d[50],rt[M<<1],to[M<<6][2],sum[M<<6];
24 inline void split(int k){
25     int len=0; while(k) d[++len]=k&1,k>>=1;
26     for(int i=len+1;i<=32;++i) d[i]=0;
27 }
28 inline void update(int& root,int las){
29     int now=root=++cnt; sum[now]=sum[las]+1;
30     for(int i=32;i;--i){
31         to[now][d[i]^1]=to[las][d[i]^1];
32         to[now][d[i]]=++cnt,las=to[las][d[i]];
33         sum[now=cnt]=sum[las]+1;
34     }
35 }
36 inline ll query(int u,int v){
37     ll ans=0;
38     for(int i=32;i;--i){
39         if(sum[to[v][d[i]^1]]-sum[to[u][d[i]^1]])
40             ans|=1ll<<i-1,u=to[u][d[i]^1],v=to[v][d[i]^1];
41         else u=to[u][d[i]],v=to[v][d[i]];
42     } return ans;
43 }
44 int main(){
45     n=read(),m=read(),update(rt[0],0); int x,y,l,r,s,i,j; ll ans=0;
46     for(i=1;i<=n;++i) a[i]=read()^a[i-1],split(a[i]),update(rt[i],rt[i-1]);
47     for(block=(int)sqrt(n+1)+1,i=0;i<=n;i+=block) for(j=i+1;j<=n;++j)
48         split(a[j]),f[i/block][j]=max(1ll*f[i/block][j-1],query(i?rt[i-1]:0,rt[j-1]));
49     while(m--){
50         x=read(),y=read(),
51         r=max((1ll*x+ans)%n+1,(1ll*y+ans)%n+1),
52         s=l=min((1ll*x+ans)%n+1,(1ll*y+ans)%n+1)-1;
53         while(s%block && s<r) ++s;
54         if(s==r){
55             for(ans=0,j=l+1;j<=r;++j)
56                 split(a[j]),ans=max(ans,query(l?rt[l-1]:0,rt[j-1]));
57         } else{
58             for(ans=f[s/block][r],j=s-1;j>=l;--j)
59                 split(a[j]),ans=max(ans,query(rt[j],rt[r]));
60         } print(ans);
61     } Ot(); return 0;
62 }

emmmmm...可持久化 trie 的题还是蛮少的...

原文地址:https://www.cnblogs.com/Judge/p/9498797.html

时间: 2024-10-13 11:26:57

可持久化 trie 的简单入门的相关文章

[您有新的未分配科技点]可,可,可持久化!?------0-1Trie和可持久化Trie普及版讲解

这一次,我们来了解普通Trie树的变种:0-1Trie以及在其基础上产生的可持久化Trie(其实,普通的Trie也可以可持久化,只是不太常见) 先简单介绍一下0-1Trie:一个0-1Trie节点只有两个子节点,分别代表0和1:从根节点开始,第一层代表限制的最高位,依次往下直到最底层,代表二进制第0位. 0-1Trie上的一条链所表示的数字,就是Trie树中的一个数字.0-1Trie除了节点和插入方式与普通的Trie树略有不同之外,其他操作都是和Trie树完全一样的.在维护这个节点插入过的siz

可持久化trie 学习总结

QAQ 以前一直觉得可持久化trie很难,今天强行写了一发觉得还是蛮简单的嘛 自己的模板是自己手写的,写了几道题目并没有出过错误 THUSC的第二题的解法五貌似就是可持久化trie,时间复杂度O(60*n*logn) 不过并没有正解优,听说考场上有人写可持久化树链剖分,也是6得不行QAQ 可持久化trie就是你每次插入一个单词的时候将原来trie的代码每次向下走的时候新建节点 把当前节点信息拷贝给新建节点,通常情况下还要额外对于trie的每个节点维护子树的信息 BZOJ 3261 也算是经典题目

[BZOJ3261&amp;BZOJ3166]可持久化trie树及其应用

可持久化trie树 可持久化trie树现在想来是比较好理解的了,但却看了一个下午... 相当于对于每个状态建立一条链(或者说一棵trie),求解的时候只要让两个点按照相同的步子走然后看sum的大小关系即可. tr[y].son[p xor 1]:=tr[x].son[p xor 1]; tr[y].sum:=tr[x].sum+1; 这两句要好好体会,对之后理解query过程中的语句很有帮助. if (tr[tr[x].son[p xor 1]].sum=tr[tr[x].son[p xor 1

bzoj3261: 最大异或和 可持久化trie

题意:给定一个非负整数序列{a},初始长度为N. 有M个操作,有以下两种操作类型: 1.Ax:添加操作,表示在序列末尾添加一个数x,序列的长度N+1. 2.Qlrx:询问操作,你需要找到一个位置p,满足l<=p<=r,使得: a[p] xor a[p+1] xor ... xor a[N] xor x 最大,输出最大是多少. 题解:可持久化trie 用前缀异或来建树,查询就变成了last^x和l到r中a[p]异或最大值是多少 先插入一个0,然后像可持久化线段树那样建树即可,还是挺简单的 /**

CQRS简单入门(Golang)

一.简单入门之入门 CQRS/ES和领域驱动设计更搭,故整体分层沿用经典的DDD四层.其实要实现的功能概要很简单,如下图. 基础框架选择了https://github.com/looplab/eventhorizon,该框架功能强大.示例都挺复杂的,囊括的概念太多,不太适合入门,所以决定在其基础上,进行简化. 二.简化使用eventhorizon Eventhorizon已经提供了详尽的使用案例(https://github.com/looplab/eventhorizon/tree/maste

【BZOJ2741】【块状链表+可持久化trie】FOTILE模拟赛L

Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r. 为了体现在线操作,对于一个询问(x,y): l = min ( ((x+lastans) mod N)+1 , ((y+lastans) mod N)+1 ).r = max ( ((x+lastans) mod N)+1 , ((y+last

正则表达式简单入门

 正则表达式简单入门    正则表达式在平常编程中有着大量的应用,对于任何一个想学习编程的人来说,正则表达式是一个必须掌握的知识. 废话不多说,下面先对正则表达式做一个简单的入门介绍,在后续的文章中,将会进行详细的介绍.    一.元字符 元字符一共有12个:$ ( ) [ { ? + * . ^ \ | 元字符有特殊的含义,如果要使用其字面值,则必须对其进行转义. 如: \$  \*  \( 等等 二.控制字符或不可打印字符 \a  警报 \e  退出 \f  换页 \n  换行 \r 

bzoj4103异或运算 可持久化trie树

要去清华冬令营了,没找到2016年的题,就先坐一坐15年的. 因为n很小,就按照b串建可持久化trie树,a串暴力枚举. 其他的直接看代码. #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; inline int read() { int x=0,f=1,ch=getchar(); while(ch<'0'||ch

BZOJ 3261: 最大异或和 [可持久化Trie]

3261: 最大异或和 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1513  Solved: 657[Submit][Status][Discuss] Description 给定一个非负整数序列 {a},初始长度为 N.       有   M个操作,有以下两种操作类型: 1 .A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1.2 .Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得: a[p]