Как на бинарном боре найти максимальный XOR пары чисел из массива?
Классическая задача: дан массив, найти максимум a[i] XOR a[j]. Наивно O(n^2). Везде советуют «бинарный бор по битам». Не понимаю, как уложить числа в бор и почему жадный спуск даёт максимум.
2 ответа
Числа кладём в бор как двоичные строки фиксированной длины (например 30 бит), старший бит — у корня. Чтобы максимизировать XOR с запрашиваемым числом, на каждом бите жадно пытаемся пойти в противоположный бит — тогда в этом разряде XOR даст 1, что весомее всех младших разрядов вместе.
struct XorTrie {
static const int B = 30;
vector<array<int,2>> t{{ -1,-1 }};
void insert(int x) {
int v = 0;
for (int b = B; b >= 0; --b) {
int bit = (x >> b) & 1;
if (t[v][bit] == -1) { t[v][bit] = t.size(); t.push_back({-1,-1}); }
v = t[v][bit];
}
}
int query_max(int x) { // макс XOR x с числом из бора
int v = 0, res = 0;
for (int b = B; b >= 0; --b) {
int bit = (x >> b) & 1;
int want = bit ^ 1; // хотим противоположный бит
if (t[v][want] != -1) { res |= (1 << b); v = t[v][want]; }
else v = t[v][bit];
}
return res;
}
};
Алгоритм: вставляем все числа, для каждого a[i] спрашиваем query_max(a[i]), берём максимум. Время — O(n · B) = O(n·30), память — O(n·B). Жадность корректна, потому что старший установленный бит результата важнее любого набора младших.
Грабли с числом бит: для a[i] < 2^30 хватает B=29..30; для long long до 2^63 берите B=62 и 1LL << b, иначе обрежете старшие биты и получите WA. И аккуратно с (1 << b) при b >= 31 — это UB на int, нужно (1LL << b).