一顆帶點權的樹,每次查詢指定兩個點,求在兩個點之間的這條路徑(包括兩端)上選任意個數能獲得的最大異或值。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)); } }