超级钢琴+可持久化$Trie$
同样设三元组 $(o,l,r)$ 表示左端点为 $o$,右端点 $in [l,r]$ 的区间的最大异或值,这个东西可以用可持久化 $Trie$ 来维护
一开始把所有 $(i,i,n)$ 扔到堆里,然后每次取出计算贡献,设取得最大异或值的位置为 $t$,然后再把 $(o,l,t-1)$ 和 $(o,t+1,r)$ 扔到堆里
具体还是看代码,很容易理解
注意可能爆 $int$,所以要开 $unsigned int$,要注意代码常数
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<queue> using namespace std; typedef long long ll; typedef unsigned int uint; inline uint read() { uint x=0; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x; } const int N=1e6+7,M=1e7+7e6; uint n,K,sum[N],rt[N],t[M],pos[M],c[M][2]; namespace Trie { uint cnt=0; void ins(uint &o,int p,uint pre,uint v,uint ps) { o=++cnt; t[o]=t[pre]+1; if(p<0) { pos[o]=ps; return; } int d=(v>>p)&1; c[o][d^1]=c[pre][d^1]; ins(c[o][d],p-1,c[pre][d],v,ps); } uint query(uint o,int p,uint pre,uint v) { if(p<0) return pos[o]; int d=(v>>p)&1; if(t[c[o][d^1]]-t[c[pre][d^1]]>0) return query(c[o][d^1],p-1,c[pre][d^1],v); else return query(c[o][d],p-1,c[pre][d],v); } } struct dat { uint o,l,r,t; dat (uint o,uint l,uint r) : o(o),l(l),r(r),t(Trie::query(rt[r],31,rt[l-1],sum[o-1])) {} inline bool operator < (const dat &tmp) const { return (sum[t]^sum[o-1])<(sum[tmp.t]^sum[tmp.o-1]); } }; priority_queue <dat> Q; ll ans; int main() { n=read(),K=read(); uint a; Trie::ins(rt[0],31,0,0,0); for(int i=1;i<=n;i++) { a=read(); sum[i]=sum[i-1]^a; Trie::ins(rt[i],31,rt[i-1],sum[i],i); } for(int i=1;i<=n;i++) Q.push(dat(i,i,n)); while(K--) { dat T=Q.top(); ans+=(sum[T.t]^sum[T.o-1]); Q.pop(); if(T.l<T.t) Q.push(dat(T.o,T.l,T.t-1)); if(T.r>T.t) Q.push(dat(T.o,T.t+1,T.r)); } cout<<ans<<endl; return 0; }