Nikitosh 和异或 —— 一道 trie 树的题用可持久化 trie 水 然后翻车了...

题意简介

题目就是叫你找两个不重合的非空区间,使得这两个区间里的数异或后相加的和最大

(看到异或,没错就决定是你了可持久化trie!)

思路

水一波字典树,莫名觉得这题可持久化能过,于是水了一发挂了,造了一波数据,然后发现是自己在做完一遍可持久化之后cnt 没有清零....

其实要用可持久化trie 来做的话也就是常规操作(话说普通字典树不也是常规操作?)

也就是前缀和往可持久化trie 上update , 然后每个 L[i]、R[i] 记录当前点为右(左)区间的最大区间异或和

然后就是枚举断点了,考虑我们枚举到的断点前的那个区间其实是确定的(异或和最大的那个),

那么我们拿当前断点作为第二个 区间的左端点,前面的区间由 lef 变量不断更新,最后就能累加出答案。

于是没什么好说的了,板子题。

代码如下

 1 //by Judge
 2 #include<iostream>
 3 #include<cstdio>
 4 using namespace std;
 5 const int M=4e5+111;
 6 //#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 7 char buf[1<<21],*p1=buf,*p2=buf;
 8 inline int read(){
 9     int x=0,f=1; char c=getchar();
10     for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
11     for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
12 }
13 int n,cnt,a[M],L[M],R[M];
14 int d[35],rt[M<<2],son[M<<5][2],sum[M<<5];
15 inline void split(int k){ //换二进制
16     int i,len=0;
17     while(k) d[++len]=k&1,k>>=1;
18     for(int i=len+1;i<=31;++i) d[i]=0;
19 }
20 inline void update(int& now,int las){ //可持久化的更新
21     sum[now=++cnt]=sum[las]+1;
22     int i,tmp=now;
23     for(i=31;i;--i){
24         son[tmp][d[i]^1]=son[las][d[i]^1],
25         son[tmp][d[i]]=++cnt,las=son[las][d[i]],
26         sum[tmp=cnt]=sum[las]+1;
27     }
28 }
29 inline int query(int u,int v){ //询问区间内与当前数的最大异或和
30     int ans=0,i;
31     for(i=31;i;--i){
32         if(sum[son[v][d[i]^1]]-sum[son[u][d[i]^1]]>0)
33             ans|=(1<<i-1),u=son[u][d[i]^1],v=son[v][d[i]^1];
34         else u=son[u][d[i]],v=son[v][d[i]];
35     } return ans;
36 }
37 int main(){  //分函数都是常规操作(因为我都是直接搞了自己的板子)
38     int x,lef,res=0;
39     n=read(),++n;
40     split(0),update(rt[1],rt[0]);
41     for(int i=2;i<=n;++i)
42         a[i]=read();
43     for(int i=2,sum=0;i<=n;++i){
44         split(sum^=a[i]),
45         update(rt[i],rt[i-1]),
46         L[i]=query(rt[0],rt[i]);
47     }
48     cnt=0,split(0),update(rt[1],rt[0]); //清零,从后往前再来一遍
49     for(int i=n,sum=0;i>=2;--i){
50         split(sum^=a[i]);
51         update(rt[n-i+2],rt[n-i+1]),
52         R[i]=query(rt[0],rt[n-i+2]);
53     } lef=L[2];
54     for(int i=3;i<=n;++i){ //从左到右处理答案
55         res=max(res,lef+R[i]),
56         lef=max(lef,L[i]);
57     } printf("%d
",res); return 0;
58 }
原文地址:https://www.cnblogs.com/Judge/p/9533071.html