P5283 异或粽子(Trie)
目录
Description
有 n 个数,任选两个数 \(1<=L<=R<=n\),使得 \(k\) 个 \([L,\; R]\) 的区间异或和最大
State
\(1<=n,\; k <=5*10^5\)
\(0<=a[i]<=4294967295\)
Input
3 2
1 2 3
Output
6
Solution
在这里提供三种解法,代码为第三种解法:
1.对于每一个 \(i∈[1,\; n]\) 在区间 \([i,\; n]\) 内寻找一个位置 \(id\) ,使得 \(sum[id]⊕sum[i]\) 最大,将这 \(n\) 个最大值放入堆中,依次取出,再将区间分为 \([i,\; id - 1]\) 和 \([id + 1, \; n]\) 即可,直至挑选 \(k\) 个
2.由于\(\forall i,\; \exists j,\; sum[i]⊕sum[j]\) 最大,但是由于题目中 \(i<=j\) 所以将 \(k=k*2\),在区间 \([1,\; n]\) 上寻找 \(\forall i\) 的前 \(k\) 大值
3.类似于解法 2, 但是可以将 \(j\) 固定于 \([i, \; n]\) 区间上寻找每一个 \(i\) 的前 \(k\) 大值,这时就需要可持久化 \(Trie\) 了,也因为如此,其需要的空间比上面两种要更大一点 \((hack)\)
Code
const int N = 5e5 + 5;
ll n, m, _;
int i, j, k;
ll a[N];
int ch[N * 40][2], sz[N * 40];
int tot = 0, root[N];
void ins(int &x, int y, ll c)
{
x = ++ tot;
int nx = x, ny = y;
for(int i = 33; ~ i; i --){
int id = (c >> i) & 1;
ch[nx][0] = ch[ny][0];
ch[nx][1] = ch[ny][1];
ch[nx][id] = ++ tot;
nx = ch[nx][id];
ny = ch[ny][id];
sz[nx] = sz[ny] + 1;
}
}
ll query(int rk, ll c, int x, int y)
{
ll ans = 0;
for(int i = 33; ~ i; i --){
int id = (c >> i) & 1;
int size = sz[ch[y][!id]] - sz[ch[x][!id]];
if(size >= rk){
ans |= (1ll << i);
x = ch[x][!id];
y = ch[y][!id];
}
else{
rk -= size;
x = ch[x][id];
y = ch[y][id];
}
}
return ans;
}
struct Node
{
int rk, id;
ll val;
int l, r;
Node(){}
Node(int id, int rk){
this -> id = id;
this -> rk = rk;
l = id, r = n;
val = query(rk, a[id], root[l], root[r]);
}
bool operator<(Node o) const{
return val < o.val;
}
};
signed main()
{
//IOS;
while(~ sdd(n, k)){
rep(i, 1, n){
sll(a[i]);
a[i] ^= a[i - 1];
}
priority_queue<Node> q;
ins(root[0], root[0], 0ll);
rep(i, 1, n){
ins(root[i], root[i - 1], a[i]);
}
rep(i, 0, n - 1){
q.push(Node(i, 1));
}
ll ans = 0;
rep(i, 1, k){
Node top = q.top();
q.pop();
ans += top.val;
if(top.val != 0) q.push(Node(top.id, top.rk + 1));
}
pll(ans);
}
return 0;
}

浙公网安备 33010602011771号