先对其求出前缀异或和,然后$o(k)$次枚举,每次选择最大值,考虑如何维护
可以全局开一个堆,维护出每一个点的最大值的最大值,那么相当于要在一个点中删去一个点再找到最大值
将这些删去的点重新建成一颗trie树,与所有数构成的trie树减一下,就可以找到新的最大值了,再用堆维护即可
有一些细节:1.数值范围较大,需要开long long;2.由于无法判断位置关系,因此要取2k个并将答案除以2
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 500005 4 #define ll long long 5 set<pair<ll,int> >s; 6 int V,n,m,ch[N*70][2],sz[N*70]; 7 ll ans,a[N]; 8 void add(int k,ll x){ 9 sz[k]++; 10 for(int i=31;i>=0;i--){ 11 int p=((((1LL<<i)&x)>0)); 12 if (!ch[k][p])ch[k][p]=++V; 13 k=ch[k][p]; 14 sz[k]++; 15 } 16 } 17 ll query(int k1,int k2,ll x){ 18 ll ans=0; 19 for(int i=31;i>=0;i--){ 20 int p=(((1LL<<i)&x)==0); 21 if (sz[ch[k1][p]]==sz[ch[k2][p]])p^=1; 22 ans+=p*(1LL<<i); 23 k1=ch[k1][p]; 24 k2=ch[k2][p]; 25 } 26 return ans; 27 } 28 int main(){ 29 scanf("%d%d",&n,&m); 30 for(int i=1;i<=n;i++){ 31 scanf("%lld",&a[i]); 32 a[i]^=a[i-1]; 33 } 34 V=n+2; 35 for(int i=0;i<=n;i++)add(1,a[i]); 36 for(int i=0;i<=n;i++)s.insert(make_pair(-(a[i]^query(1,i+2,a[i])),i)); 37 m*=2; 38 for(int i=1;i<=m;i++){ 39 ans-=(*s.begin()).first; 40 int k=(*s.begin()).second; 41 s.erase(s.begin()); 42 add(k+2,query(1,k+2,a[k])); 43 s.insert(make_pair(-(a[k]^query(1,k+2,a[k])),k)); 44 } 45 printf("%lld",ans/2); 46 }