D2. 388535 (Hard Version)
题意:给出 l , r l,r l,r,和一个序列 a a a, a i a_i ai由 l , r l,r l,r中的一个数异或 x x x得到,问 x x x可以取什么值。
思路: l , r l,r l,r中的每个元素互不相同,我们只要确定一个 x x x, m i n { x ⨁ a [ i ] ∣ i ∈ [ 1 , r − l + 1 ] } = l min\{x \bigoplus a[i] ~|~i \in[1, r-l+1] \}=l min{x⨁a[i] ∣ i∈[1,r−l+1]}=l, m a x { x ⨁ a [ i ] ∣ i ∈ [ 1 , r − l + 1 ] } = r max\{x \bigoplus a[i] ~|~i \in[1, r-l+1] \}=r max{x⨁a[i] ∣ i∈[1,r−l+1]}=r,这样就能保证 a [ i ] a[i] a[i]是由 [ l , r ] [l,r] [l,r]和 x x x异或得到。
b [ i ] = a [ i ] ⨁ l b[i] = a[i] \bigoplus l b[i]=a[i]⨁l一定存在 x x x,所以我们就是去找哪一个 b [ i ] b[i] b[i]符条件。 01 01 01字典树。
(注意清空细节😥😥🤕😥😥😥)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+10;
int a[N];
int nex[N*20][2], cnt;
void insert(int x) {
int p = 0;
for(int i=17; i>=0; i--) {
int c = ((x >> i) & 1);
if(!nex[p][c]) {
nex[p][c] = ++cnt;
nex[cnt][0] = nex[cnt][1] = 0; //把下一层清空,优化清空。
}
p = nex[p][c];
}
}
int querymx(int x) {
int p = 0, ans = 0;
for(int i=17; i>=0; i--) {
int c = ((x >> i) & 1);
if(nex[p][!c]) p = nex[p][!c], ans ^= (1 << i);
else p = nex[p][c];
}
return ans;
}
int querymi(int x) {
int p = 0, ans = 0;
for(int i=17; i>=0; i--) {
int c = ((x >> i) & 1);
if(nex[p][c]) p = nex[p][c];
else p = nex[p][!c], ans ^= (1 << i);
}
return ans;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int t;
scanf("%d", &t);
while(t--) {
int l, r;
scanf("%d%d", &l, &r);
if(l == 0) {
for(int i=1; i<=r-l+1; i++) {
scanf("%d", &a[i]);
}
int ans = 0;
for(int i=0; i<=18; i++) {
int cnt = 0;
for(int j=l; j<=r; j++) {
if((a[j-l+1] >> i) & 1) cnt--;
if((j >> i) & 1) cnt++;
}
if(cnt) ans ^= (1 << i);
}
printf("%d\n", ans);
continue;
}
for(int i=1; i<=r-l+1; i++) {
int x;
scanf("%d", &x);
insert(x);
a[i] = x^l;
}
for(int i=1; i<=r-l+1; i++) {
if(querymi(a[i]) == l && querymx(a[i]) == r) {
printf("%d\n", a[i]);
break;
}
}
nex[0][0] = nex[0][1] = 0;//初始化
cnt=0;
}
return 0;
}