前言
去年打酱油的时候,我还不会字典树= =
貌似我(
equire{enclose}enclose{horizontalstrike}{O(n^2logn)})的分都没拿满?
题目
讲解
异或?l~r的连续区间?
明显可以前缀和优化
接下来就变成了求前(k)大的点对异或值了
看题解得知,这种类型的问题可以这么解决:
先把所有的前缀和插入进一棵字典树中,注意要插入0
此字典树需要记录的信息有:
1.两个儿子(常规操作)
2.子树大小(记录这条路走下去可以最多选出多少个数)
然后我们可以将每一个前缀和的查询的最大值插进优先队列
每次取出最大的一个,累加答案,然后求出次大的值,放回优先队列...
循环做(k)次,就完事了
吗?
NO!由于(s_i oplus s_j=s_j oplus s_i),所以每个较大值会出现两次,我们要将(2k)个较大数累加起来,最后将答案除以二即可
时间复杂度为(O(nlog_2n))
注意开(long long)
代码
//12252024832524
#include <queue>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 500005;
const int MAXLOG = 32;
int n,k;
LL s[MAXN],ans;
LL Read()
{
LL x = 0,f = 1;char c = getchar();
while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
return x * f;
}
void Put1(LL x)
{
if(x > 9) Put1(x/10);
putchar(x%10^48);
}
void Put(LL x,char c = -1)
{
if(x < 0) putchar('-'),x = -x;
Put1(x);
if(c >= 0) putchar(c);
}
template <typename T>T Max(T x,T y){return x > y ? x : y;}
template <typename T>T Min(T x,T y){return x < y ? x : y;}
template <typename T>T Abs(T x){return x < 0 ? -x : x;}
struct Node
{
int ID,rk;
LL val;
Node(){}
Node(int ID1,int rk1,LL val1){
ID = ID1;
rk = rk1;
val = val1;
}
bool operator < (const Node &px) const{
return val < px.val;
}
};
priority_queue<Node> q;
int tot;
struct node
{
int ch[2],siz;
}t[MAXN * MAXLOG];
void ins(LL x)
{
int now = 0;
for(int i = MAXLOG - 1;i >= 0;-- i)
{
bool ID = x >> i & 1;
if(!t[now].ch[ID]) t[now].ch[ID] = ++tot;
now = t[now].ch[ID];
t[now].siz++;
}
}
LL query(int rk,LL w)
{
int now = 0;
LL ret = 0;
for(int i = MAXLOG - 1;i >= 0;-- i)
{
bool ID = w >> i & 1,to = ID ^ 1;
if(t[now].ch[to])
{
if(t[t[now].ch[to]].siz >= rk) now = t[now].ch[to],ret += 1ll << i;
else rk -= t[t[now].ch[to]].siz,now = t[now].ch[ID];
}
else now = t[now].ch[ID];
}
return ret;
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n = Read(); k = Read() << 1;
for(int i = 1;i <= n;++ i) s[i] = Read() ^ s[i-1];
for(int i = 0;i <= n;++ i) ins(s[i]);
for(int i = 0;i <= n;++ i) q.push(Node(i,1,query(1,s[i])));
while(k--)
{
Node g = q.top(); q.pop(); ans += g.val;
if(g.rk < n) q.push(Node(g.ID,g.rk+1,query(g.rk+1,s[g.ID])));
}
Put(ans >> 1);
return 0;
}