1. 程式人生 > >Nikitosh 和異或 —— 一道 trie 樹的題用可持久化 trie 水 然後翻車了...

Nikitosh 和異或 —— 一道 trie 樹的題用可持久化 trie 水 然後翻車了...

普通 就是 ... str strong 記錄 clas 自己 相加

題意簡介

題目就是叫你找兩個不重合的非空區間,使得這兩個區間裏的數異或後相加的和最大

(看到異或,沒錯就決定是你了可持久化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\n",res); return 0; 58 }

Nikitosh 和異或 —— 一道 trie 樹的題用可持久化 trie 水 然後翻車了...