小水题.主要是线性基快忘光了.

Description

询问链上任意选数异或最大值.

Solution

树剖+线段树+线性基合并. $\log^4{n}$也可过.

探讨了一下直接在重链上维护前缀线性基的做法, 事实上跳lca最后一段不一定是前缀.

倍增就是拿空间换了时间.

听说还有点分做法?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int maxn = 20005;

struct edge {
int to, nxt;
}e[maxn << 1];
int n, q, lnk[maxn], ptr;
int dfn[maxn], cnt, top[maxn], f[maxn];
int dep[maxn], siz[maxn], mxson[maxn];
ll a[maxn], w[maxn];
struct LB {
ll v[61];
ll& operator[](int x) {
return v[x];
}
}s[maxn << 2], ans;

inline int rd() {
register int x = 0, c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
return x;
}
inline ll rdll() {
register ll x = 0; register int c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
return x;
}
inline void add(int bgn, int end) {
e[++ptr] = (edge){end, lnk[bgn]};
lnk[bgn] = ptr;
}
void dfs1(int x, int fa) {
dep[x] = dep[fa] + 1;
siz[x] = 1;
f[x] = fa;
for (int p = lnk[x]; p; p = e[p].nxt) {
int y = e[p].to;
if (y == fa) continue;
dfs1(y, x);
siz[x] += siz[y];
if (siz[y] > siz[mxson[x]]) mxson[x] = y;
}
}
void dfs2(int x, int init) {
top[x] = init;
dfn[x] = ++cnt;
w[cnt] = a[x];
if (!mxson[x]) return;
dfs2(mxson[x], init);
for (int p = lnk[x]; p; p = e[p].nxt) {
int y = e[p].to;
if (y == mxson[x] || y == f[x]) continue;
dfs2(y, y);
}
}
void merge(LB &res, LB &l, LB &r) {
LB ret;
for (int i = 60; ~i; --i) ret[i] = l[i];
for (int i = 60; ~i; --i)
if (r[i]) {
ll p = r[i];
for (int i = 60; ~i; --i)
if (p & (1ll << i)) {
if (!ret[i]) {
ret[i] = p; break;
} else p ^= ret[i];
}
}
for (int i = 60; ~i; --i)
res[i] = ret[i];
}
void build(int cur, int l, int r) {
if (l == r) {
ll p = w[l];
for (int i = 60; ~i; --i)
if (p & (1ll << i)) {
if (!s[cur][i]) {
s[cur][i] = p; break;
} else p ^= s[cur][i];
}
return;
}
int mid = (l + r) >> 1;
build(cur << 1, l, mid);
build(cur << 1|1, mid + 1, r);
merge(s[cur], s[cur << 1], s[cur << 1|1]);
}
void query(int cur, int l, int r, int L, int R) {
if (L <= l && r <= R) {
merge(ans, ans, s[cur]);
return;
}
int mid = (l + r) >> 1;
if (L <= mid) query(cur << 1, l, mid, L, R);
if (R > mid) query(cur << 1|1, mid + 1, r, L, R);
}
void queryt(int x, int y) {
memset(ans.v, 0, sizeof ans.v);
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
query(1, 1, n, dfn[top[x]], dfn[x]);
x = f[top[x]];
}
if (dep[x] > dep[y]) swap(x, y);
query(1, 1, n, dfn[x], dfn[y]);
}

int main() {
n = rd(); q = rd();
for (int i = 1; i <= n; ++i)
a[i] = rdll();
int u, v;
for (int i = 1; i < n; ++i) {
u = rd(); v = rd();
add(u, v); add(v, u);
}
dfs1(1, 0);
dfs2(1, 1);
build(1, 1, n);
while (q--) {
u = rd(); v = rd();
queryt(u, v);
ll res = 0;
for (int i = 60; ~i; --i) {
if ((res ^ ans[i]) > res)
res ^= ans[i];
}
printf("%lld\n", res);
}
return 0;
}