考场上想到了没打完,细节思路还是不是很优,我原先的想法是每一次找完后标记那个点,下次再继续找(并不是这个意思,说不清楚)但实际上和平衡树一样加个大小就很好写了
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN=500005; const int DEP=31; int N,M; ll ans,s[MAXN]; struct node{ ll val; int x,k; bool operator <(const node& A) const { return val<A.val; } }; priority_queue<node> q; struct Node{ int ch[2],sum; }trie[MAXN*(DEP+2)]; int head[MAXN],cnt; void insert(Node c,Node& u,ll val,int d){ u.sum=c.sum+1; if(d<0) return; int x=(val>>d)&1ll; u.ch[!x]=c.ch[!x]; insert(trie[c.ch[x]],trie[u.ch[x]=++cnt],val,d-1); } ll query(Node u,ll val,int d,int k){ if(d<0) return 0; int x=(val>>d)&1; int lsum=trie[u.ch[!x]].sum; if(lsum>=k) return ((ll)1<<d)+(ll)query(trie[u.ch[!x]],val,d-1,k); return (ll)query(trie[u.ch[x]],val,d-1,k-lsum); } int main(){ trie[0].ch[0]=trie[0].ch[1]=trie[0].sum=0; insert(trie[0],trie[head[0]=++cnt],0,DEP); scanf("%d%d",&N,&M); for(int i=1;i<=N;++i){ ll a; scanf("%lld",&a); s[i]=s[i-1]^a; insert(trie[head[i-1]],trie[head[i]=++cnt],s[i],DEP); q.push((node){query(trie[head[i-1]],s[i],DEP,1),i,1}); } for(int i=1;i<=M;++i){ ans+=q.top().val; int x=q.top().x,k=q.top().k; q.pop(); if(k==x) continue; q.push((node){query(trie[head[x-1]],s[x],DEP,k+1),x,k+1}); } printf("%lld",ans); return 0; }