効果の件名:
トピックリンク:https://www.luogu.org/problemnew/show/P5283
見出される配列与えられました
間隔
このような最大間隔とXORこと。
アイデア:
問題が変換されるように、それは最初の接頭辞のXOR、見つけるために行います
の
その結果、
できるだけ大きいです。
お知らせ
、選出された場合のように
、再度選択します
。だから我々は、回数を求めることができます
、各二つの連続するクエリが同じに設定されるように
。ライン上の2最終的な答えで割りました。
私たちは、それぞれの意志、ヒープを維持します
、対応します
の最大
、反応器、スタックの各取ら呼び掛けトップ、大次内部スロー
ヒープに投げ込ま。
以下のために
を求めます
作り
第として
大明らかにすることができます
メンテナンス。たびに左右の部分木に値を決定するために使用する権利。
だから、永続的に使用することはできません
この質問の完成へ。時間複雑
。
コード:
#include <queue>
#include <cstdio>
#include <string>
#include <iostream>
#define mp make_pair
using namespace std;
typedef long long ll;
const int N=500010,LG=35;
int n,m,tot=1,trie[N*LG][2],cnt[N],size[N*LG];
ll a[N],ans;
priority_queue<pair<ll,int> > q;
ll read()
{
ll d=0;
char ch=getchar();
while (!isdigit(ch)) ch=getchar();
while (isdigit(ch))
d=(d<<3)+(d<<1)+(ll)ch-48LL,ch=getchar();
return d;
}
void insert(ll x)
{
int p=1;
for (int i=LG;i>=0;i--)
{
int id=(x>>(ll)i)&1;
if (!trie[p][id]) trie[p][id]=++tot;
p=trie[p][id];
size[p]++;
}
}
ll find(ll x,int k)
{
int p=1;
ll ans=0;
for (int i=LG;i>=0;i--)
{
int id=(x>>(ll)i)&1;
if (trie[p][id^1]&&size[trie[p][id^1]]>=k)
{
ans=(ans<<1)|1;
p=trie[p][id^1];
}
else if (trie[p][id])
{
k-=size[trie[p][id^1]];
ans<<=1;
p=trie[p][id];
}
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
insert(0); cnt[0]=1;
for (int i=1;i<=n;i++)
{
a[i]=read();
a[i]^=a[i-1];
insert(a[i]);
cnt[i]=1;
}
for (int i=0;i<=n;i++)
q.push(mp(find(a[i],1),i));
m*=2;
while (m--)
{
if (!q.size()) break;
ans+=q.top().first;
int i=q.top().second;
q.pop();
cnt[i]++;
if (cnt[i]<=n+1)
q.push(mp(find(a[i],cnt[i]),i));
}
cout<<ans/2LL;
return 0;
}