一颗带点权的树,每次查询指定两个点,求在两个点之间的这条路径(包括两端)上选任意个数能获得的最大异或值。node
考虑倍增维护LCA,同时维护向上\(2^k\)的点的线性基,而后查询求LCA时将通过的全部线性基暴力合并便可。spa
#include <cmath> #include <cstdio> #include <cstring> template <class T> inline void read(T &num) { bool flag = 0; num = 0; char c = getchar(); while ((c < '0' || c > '9') && c != '-') c = getchar(); if (c == '-') { flag = 1; c = getchar(); } num = c - '0'; c = getchar(); while (c >= '0' && c <= '9') num = (num << 3) + (num << 1) + c - '0', c = getchar(); if (flag) num *= -1; } template <class T> inline void output(T num) { if (num < 0) { putchar('-'); num = -num; } if (num >= 10) output(num / 10); putchar(num % 10 + '0'); } template <class T> inline void outln(T num) { output(num); putchar('\n'); } template <class T> inline void outps(T num) { output(num); putchar(' '); } template <class T> inline T max(T a, T b) { return a < b ? b : a; } typedef long long ll; struct basis // 线性基 { typedef ll type; static const int W = 62; type s[W]; basis() { memset(s, 0, sizeof(s)); } void ins(type x) // 向线性基内插入一个数 { for (int i = W; i >= 1; i--) { if (x >> (i - 1)) { if (s[i] == 0) { s[i] = x; return; } x ^= s[i]; } } } type maxxor() // 求线性基内最大xor值 { type ans = 0; for (int i = W; i >= 1; i--) { ans = max(ans, ans ^ s[i]); } return ans; } }; const int N = 20005; const int lN = 20; int n, q, ln; namespace graph // 存图 { int fir[N], to[N * 2], nxt[N * 2], ecnt; void add_edge(int u, int v) { to[++ecnt] = v; nxt[ecnt] = fir[u]; fir[u] = ecnt; } } // namespace graph namespace tree { ll g[N]; // g[i] : i号点的数字 int dep[N]; // dep[i] : i号点的深度 int fa[N][lN]; // fa[i][j] : i号点向上跳2^j到达的节点 basis b[N][lN]; // b[i][j] : i号点以上的2^j点的线性基(显然不包括fa[i][j]) void dfs(int node, int f) // 深搜初始化 { using namespace graph; dep[node] = dep[f] + 1; fa[node][0] = f; b[node][0].ins(g[node]); for (int i = 1; i <= ln; i++) // 倍增求2^k次祖先以及路径上数字的线性基 { fa[node][i] = fa[fa[node][i - 1]][i - 1]; if (!fa[node][i]) break; for (int j = 1; j <= basis::W; j++) { if (b[node][i - 1].s[j]) b[node][i].ins(b[node][i - 1].s[j]); if (b[fa[node][i - 1]][i - 1].s[j]) b[node][i].ins(b[fa[node][i - 1]][i - 1].s[j]); } } for (int e = fir[node]; e; e = nxt[e]) { if (to[e] == f) continue; dfs(to[e], node); } } } // namespace tree ll solve(int x, int y) { using namespace tree; basis rtn; if (dep[x] < dep[y]) x ^= y ^= x ^= y; for (int k = ln; k >= 0; k--) if (dep[fa[x][k]] >= dep[y]) { for (int j = 1; j <= basis::W; j++) if (b[x][k].s[j]) rtn.ins(b[x][k].s[j]); x = fa[x][k]; } if (x == y) { rtn.ins(g[x]); return rtn.maxxor(); } for (int i = ln; i >= 0; i--) { if (dep[fa[x][i]] == 0) continue; if (fa[x][i] == fa[y][i]) continue; for (int j = 1; j <= basis::W; j++) { if (b[x][i].s[j]) rtn.ins(b[x][i].s[j]); if (b[y][i].s[j]) rtn.ins(b[y][i].s[j]); } x = fa[x][i]; y = fa[y][i]; } rtn.ins(g[x]); rtn.ins(g[y]); rtn.ins(g[fa[x][0]]); return rtn.maxxor(); } int main() { read(n); read(q); ln = ceil(log(n) / log(2)) + 2; for (int i = 1; i <= n; i++) read(tree::g[i]); for (int i = 1; i < n; i++) { int x, y; read(x); read(y); graph::add_edge(x, y); graph::add_edge(y, x); } tree::dfs(1, 0); while (q--) { int x, y; read(x); read(y); outln(solve(x, y)); } }