可持久化01trie支持查询最大的区间异或和。
对于普通01trie,我们每次新建的是一条新边(也有可能不建)
而可持久化01trie就像主席树一样,每次利用历史版本新建。
一般学到可持久化01trie的都学过主席树了吧,所以我就不讲思想了
1 struct tree{ 2 LL ch[2],id,cnt; 3 }tr[N*50]; 4 LL tot=0; 5 6 void Insert(LL co,LL &now,LL k,LL pos,LL bit){ 7 // 历史版本,新建的树,数值,原序列中的位置,当前高度 8 tr[now=++tot]=tr[co];//新建节点 9 ++tr[now].cnt;//++次数 10 if(bit<0){tr[now].id=pos;return;} 11 bool c=k&(1LL<<bit);//一定要用bool,RE的血泪史。 12 Insert(tr[co].ch[c],tr[now].ch[c],k,pos,bit-1); 13 return; 14 } 15 16 inline LL query(LL l,LL r,LL k,LL bit){ 17 // 左边界,右边界,数值,高度 18 if(bit<0)return tr[r].id; 19 bool c=k&(1<<bit); 20 LL rem=tr[tr[r].ch[c^1]].cnt-tr[tr[l].ch[c^1]].cnt; 21 if(rem)return query(tr[l].ch[c^1],tr[r].ch[c^1],k,bit-1); 22 else return query(tr[l].ch[c],tr[r].ch[c],k,bit-1); 23 //贪心的选取c^1,实在没得选也就只能走c了 24 }
对于一个起点 i ,找到它与 sum[ (i,n] ] 异或的最大位置,记为pos。
开一个结构体
1 struct D{ 2 LL st; 3 LL l,r,pos;//pos可选的区间 4 LL sum;//这个可以不用存 5 bool operator < (D b) const{ 6 return sum<b.sum; 7 } 8 };
压到大根堆里,每次取出最大的,然后把 [ l , r ] 从pos那里分成两个区间,分别算出pos再压进去。
重复k次。
代码写的很仓促,某谷会TLE两个点,仅供参考。
1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cstring> 5 #include<queue> 6 #include<cctype> 7 using namespace std; 8 #define LL long long 9 const int N=500005; 10 LL n,x,k; 11 LL sum[N]; 12 struct tree{ 13 LL ch[2],id,cnt; 14 }tr[N*50]; 15 LL rt[N]; 16 LL tot=0; 17 void Insert(LL co,LL &now,LL k,LL pos,LL bit){ 18 // 历史版本,新建的树,数值,原序列中的位置,当前高度 19 tr[now=++tot]=tr[co];//新建节点 20 ++tr[now].cnt;//++次数 21 if(bit<0){tr[now].id=pos;return;} 22 bool c=k&(1LL<<bit);//一定要用bool,RE的血泪史。 23 Insert(tr[co].ch[c],tr[now].ch[c],k,pos,bit-1); 24 return; 25 } 26 27 inline LL query(LL l,LL r,LL k,LL bit){ 28 // 左边界,右边界,数值,高度 29 if(bit<0)return tr[r].id; 30 bool c=k&(1<<bit); 31 LL rem=tr[tr[r].ch[c^1]].cnt-tr[tr[l].ch[c^1]].cnt; 32 if(rem)return query(tr[l].ch[c^1],tr[r].ch[c^1],k,bit-1); 33 else return query(tr[l].ch[c],tr[r].ch[c],k,bit-1); 34 //贪心的选取c^1,实在没得选也就只能走c了 35 } 36 37 struct D{ 38 LL st; 39 LL l,r,pos; 40 LL sum; 41 bool operator < (D b) const{ 42 return sum<b.sum; 43 } 44 }; 45 46 priority_queue<D> q; 47 48 LL ans=0; 49 50 int main(){ 51 //freopen("1.in","r",stdin); 52 scanf("%lld%lld",&n,&k); 53 for(LL i=1;i<=n;++i){ 54 scanf("%lld",&x); 55 sum[i]=sum[i-1]^x; 56 } 57 for(LL i=1;i<=n;++i){ 58 Insert(rt[i-1],rt[i],sum[i],i,33); 59 } 60 for(LL i=1;i<=n;++i){ 61 LL l=i; 62 LL r=query(rt[l-1],rt[n],sum[l-1],33); 63 q.push((D){l,l,n,r,sum[r]^sum[l-1]}); 64 } 65 while(k--){ 66 D tmp=q.top();q.pop(); 67 ans+=tmp.sum; 68 LL st=tmp.st; 69 LL i=tmp.l,j=tmp.r; 70 if(i<tmp.pos){ 71 LL t=query(rt[i-1],rt[tmp.pos-1],sum[st-1],33); 72 q.push((D){st,i,tmp.pos-1,t,sum[t]^sum[st-1]}); 73 } 74 if(j>tmp.pos){ 75 LL t=query(rt[tmp.pos],rt[j],sum[st-1],33); 76 q.push((D){st,tmp.pos+1,j,t,sum[st-1]^sum[t]}); 77 } 78 } 79 cout<<ans; 80 return 0; 81 }