CF1625D (01trie应用)
Binary Spiders
选出最大的防御蜘蛛数量,最少要有两只,并且任意两只防御蜘蛛都的XOR值大于等于k。
- 令m为k的最高位1的位。则若存在两个数在m位以上的位不同,则一定大于k。
- 若m以上的位相同,则在相同的大于m位的前缀下能否找出两个数比k大,这样的数是只有两个的,因为第m位的XOR一定要是1,若am ^ bm = 1, am ^ cm = 1, bm ^ cm = 0。这一组内选一个数和其他组组也可以。
- 每个数按大于m位的二进制数分组,同组选出来两个xor能大于k的,没有就只选一个。字典树解决选两数得到最大的xor
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 5;
int a[N];
map<int, int> id;
map<int, vector<int>> mp;
int trie[N * 30][2], tot = 1;
void insert(int x) {
int p = 1;
for(int i = 30; i >= 0; -- i) {
bool k = x >> i & 1;
if(!trie[p][k]) trie[p][k] = ++ tot;
p = trie[p][k];
}
}
int query(int x) {
int p = 1; int res = 0;
for(int i = 30 ; i >= 0; -- i) {
bool u = x >> i & 1;
if(trie[p][!u]) res = res << 1 | (!u), p = trie[p][!u];
else res = res << 1 | u, p = trie[p][u];
}
return res;
}
int get_bit(int x) {
int res = 0;
while (x){
++ res;
x >>= 1;
}
return res;
}
void init() {
memset(trie, 0, sizeof (int) * 2 * (tot + 1)); tot = 1;
}
int main () {
int n, k; cin >> n >> k;
for(int i = 1; i <= n; ++ i) cin >> a[i], id[a[i]] = i;
int m = get_bit(k);
if(!k) {
cout << n << endl;
for(int i = 1; i <= n; i ++) cout << i << " ";
return 0;
}
for(int i = 1; i <= n; ++ i) {
mp[a[i] >> m].push_back(a[i]);
}
vector<int> ans;
for(auto i : mp) {
init();
for(auto j : i.second) {
insert(j);
}
bool ifin = 0;
for(auto j : i.second) {
int qx = query(j);
if((qx ^ j) >= k) {
ans.push_back(j); ans.push_back(qx); ifin = 1;
break;
}
}
if(!ifin && i.second.size()) ans.push_back(i.second[0]);
}
if(ans.size() <= 1) {
cout << -1 << endl;
} else {
cout << ans.size() << endl;
for(auto i : ans) {
cout << id[i] << " ";
}
cout << endl;
}
return 0;
}
最大异或路径
一棵树(1e5个点)中的异或路径是一条路径上的所有边权异或。
所出来根节点到每个点的dist[i],答案就是 选两个dist[i]xor起来得到的最大值。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int N = 1e5 + 5;
int h[N], w[N << 1], e[N << 1], ne[N << 1], idx;
int dist[N]; int n;
int trie[N * 32][2], tot = 1;
void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}
void init() {
for(int i = 0; i <= n; ++ i) h[i] = -1, dist[i] = 0; idx = 0;
memset(trie, 0, sizeof (int) * 2 * (tot + 1)); tot = 1;
}
void dfs(int u, int fa) {
for(int i = h[u]; ~i; i = ne[i]) {
int v = e[i]; if(v == fa) continue;
dist[v] = dist[u] ^ w[i];
dfs(v, u);
}
}
void insert(int x) {
int p = 1;
for(int i = 30; i >= 0; -- i) {
bool k = x >> i & 1;
if(!trie[p][k]) trie[p][k] = ++ tot;
p = trie[p][k];
}
}
int query(int x) {
int p = 1; int res = 0;
for(int i = 30 ; i >= 0; -- i) {
bool u = x >> i & 1;
if(trie[p][!u]) res = res << 1 | (!u), p = trie[p][!u];
else res = res << 1 | u, p = trie[p][u];
}
return res;
}
int main() {
memset(h, -1, sizeof h);
while (~scanf("%d", &n)){
for(int i = 1; i < n; ++ i) {
int u, v, c; scanf("%d %d %d", &u, &v, &c);
++ u, ++ v;
add(u, v, c); add(v, u, c);
}
dist[1] = 0;
dfs(1, -1);
int ans = 0;
for(int i = 1; i <= n; ++ i) {
insert(dist[i]);
}
for(int i = 1; i <= n; ++ i) {
ans = max(ans, query(dist[i]) ^ dist[i]);
}
printf("%d\n", ans);
init();
}
return 0;
}