题意:
如题所示,求\(S(u_1,v_1)\)\(\oplus\)\(S(u2,v2)\)的最大值。
分析:
\(1\).暴力解法:既然\(S(u,v)\)与每个点的祖先有关,那么不难想到一个\(O(n^2)\)的方法计算所有\(S(u,v)\)的值,对每个顶点遍历其祖先暴力计算即可。要算\(S(u_1,v_1)\)\(\oplus\)\(S(u_2,v_2)\)的最大值,可以暴力\(O(p^{2})\)的计算,其中\(p\)表示去重后所有\(S(u,v)\)的数目。那么总复杂度就是\(O(p^2)\)的,无法通过本题。\(p\)的最大值不超过\(20000*15\)。
\(2\).我的解法:可以发现每个顶点的权值很小,只需要用一个数组\(vis[N][16]\)来标记\(u\)的祖先到\(u\)这个节点的异或值,当\(dfs\)遍历\(u\)的儿子\(v\)时,再计算标记\(v\)的异或值即可。这样即可\(O(n*16)\)的得到所有\(S(u,v)\)的值。再用一棵\(01\)字典树边插入边查询最大值即可,总复杂度\(O(p*log_2(p))\)。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define pb push_back
const int N = 2e4 + 5, M = N * 16 + 5;
int n, u, v, ans, w[N];
bool val[N][17], flag[M];
int tot, ch[M * 19][2];
int head[N], cnt;
struct Graph {
int v, next;
} edge[N << 1];
void addedge(int u, int v) {
edge[++cnt].v = v;
edge[cnt].next = head[u];
head[u] = cnt;
}
void insert(int p) {
int u = 0, x;
for (int i = 19; ~i; i--) {
x = (p >> i) & 1;
if (!ch[u][x]) ch[u][x] = ++tot;
u = ch[u][x];
}
}
int query(int p) {
int u = 0, x, ans = 0;
for (int i = 19; ~i; i--) {
x = (p >> i) & 1;
if (ch[u][!x]) u = ch[u][!x], ans |= (1 << i);
else u = ch[u][x];
}
return ans;
}
void dfs(int u, int f) {
val[u][w[u]] = true;
if (!flag[w[u] * u]) {
flag[w[u] * u] = true;
insert(w[u] * u);
ans = max(ans, query(w[u] * u));
}
for (int i = head[u]; i; i = edge[i].next) {
int v = edge[i].v;
if (v == f) continue;
for (int j = 0; j <= 15; j++) {
if (val[u][j]) {
val[v][j ^ w[v]] = true;
if (!flag[(j ^ w[v]) * v]) {
flag[(j ^ w[v]) * v] = true;
insert((j ^ w[v]) * v);
ans = max(ans, query((j ^ w[v]) * v));
}
}
}
dfs(v, u);
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n - 1; i++) {
scanf("%d %d", &u, &v);
addedge(u, v), addedge(v, u);
}
for (int i = 1; i <= n; i++) scanf("%d", w + i);
dfs(1, 0);
printf("%d\n", ans);
return 0;
}