# 可持久化Trie+堆优化 OR Trie树上求XOR第K大 ---- P5283 [十二省联考2019]异或粽子

2021/8/21 19:16:00 浏览：

## 题目大意：

1. 考虑先做个 prefix xor 前缀异或 b i = ⨁ j = 1 i a j ( 1 ≤ i ≤ n ) b_i=\bigoplus_{j=1}^{i}a_j(1\leq i \leq n)
2. 那么就可以 O ( 1 ) O(1) 查询了
3. ⨁ i = l r a i = b r ⊕ b l − 1 \bigoplus_{i=l}^{r}a_i=b_r\oplus b_{l-1}
4. 然后考虑这样我们要解决的问题就变成了给定 n n 个数，求异或值最靠前的 k k 对。

## code 1:

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
}
ll arr[maxn];
struct Trie {
int tr[maxn * 40][2], sum[maxn *40], id[maxn * 40];
int root[maxn], cnt;
inline void insert(int &now, int pre, int val, int idx) {
now = ++ cnt;
int poi = now;
for(int i = 31; i >= 0; -- i) {
tr[poi][0] = tr[pre][0];
tr[poi][1] = tr[pre][1];
sum[poi] = sum[pre] + 1;
int c = (val >> i) & 1;
pre = tr[pre][c];
tr[poi][c] = ++ cnt;
poi = tr[poi][c];
}
sum[poi] = sum[pre] + 1;
id[poi] = idx;
}
inline int query(int rtl, int rtr, int val) {
for(int i = 31; i >= 0; -- i) {
int c = (val >> i) & 1;
if((sum[tr[rtr][c^1]] - sum[tr[rtl][c^1]]) > 0) {
rtl = tr[rtl][c^1];
rtr = tr[rtr][c^1];
} else {
rtl = tr[rtl][c];
rtr = tr[rtr][c];
}
};
return id[rtr];//返回和val异或最大那个数的下标
}
} trie;

struct node {
int l, r, id, i;
ll val;
bool operator < (const node & a) const {
return val < a.val;
}
};
priority_queue <node> q;
int main() {
IOS;
int n, m;
cin >> n >> m;
trie.insert(trie.root[1],trie.root[0],0,1);// 处理边界是1 arr[1] = 0;
for(int i = 2; i <= n + 1; ++ i) {
cin >> arr[i];
arr[i] ^= arr[i-1];
trie.insert(trie.root[i],trie.root[i-1],arr[i],i);
}
for(int i = 2; i <= n + 1; ++ i) {
int id = trie.query(trie.root[0],trie.root[i],arr[i]);
ll val = arr[id] ^ arr[i];
q.push((node){0,i,id,i,val});
}
ll ans = 0;
for(int i = 1; i <= m; ++ i) {
auto top = q.top();
q.pop();
ans += top.val;
int l = top.l, r = top.r, id = top.id, idx = top.i; // id是最大数的下标
if(l+1 < id) {
int idl = trie.query(trie.root[l],trie.root[id-1],arr[idx]); // 查询[l,id-1]
ll vall = arr[idl] ^ arr[idx];
q.push((node){l,id-1,idl,idx,vall});
}
if(id < r) {
int idr = trie.query(trie.root[id],trie.root[r],arr[idx]);//查询(id,r] = [id+1,r] 左开右闭
ll valr = arr[idr] ^ arr[idx];
q.push((node){id,r,idr,idx,valr});
}
}
cout << ans;
return 0;
}


## code 2

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args)  {
}
int tr[maxn * 40][2], cnt;
int sum[maxn * 40];
ll arr[maxn];
struct node {
int rk, i;
ll val;
bool operator < (const node & a) const {
return val < a.val;
}
};
priority_queue<node> q;
inline void insert(ll x) {
int rt = 0;
for(ll i = 31; i >= 0; -- i) {
int c = (x >> i) & 1;
if(!tr[rt][c]) tr[rt][c] = ++ cnt;
sum[rt] ++;
rt = tr[rt][c];
}
sum[rt] ++;
return;
}

inline ll ask(ll x, int kth) {
int rt = 0;
ll ans = 0;
for(ll i = 31; i >= 0; -- i) {
int c = (x >> i) & 1;
if(!tr[rt][c^1]) rt = tr[rt][c];
else if(sum[tr[rt][c^1]] < kth) kth -= sum[tr[rt][c^1]], rt = tr[rt][c]; // 类似权值线段树的跳法
else rt = tr[rt][c^1], ans |= (1ll << i);
}
return ans;
}

int main() {
//IOS;
ll n, m;
insert(0);
for(int i = 1; i <= n; ++ i) {
cin >> arr[i];
arr[i]  ^= arr[i-1];
insert(arr[i]);
}
for(int i = 0; i <= n; ++ i) q.push({1,i,ask(arr[i],1)});
ll ans = 0;
for(int i = 1; i <= 2 * m; ++ i) {
auto top = q.top();
q.pop();
ans += top.val;
}
cout << (ans >> 1);
return 0;
}