4568: [Scoi2016]幸运数字
Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 1717 Solved: 653
[ Submit][ Status][ Discuss]
Description
Input
Output
输出需要包含 q 行,每行包含 1 个非负整数,表示这名旅行者可以保留的最大幸运值。
Sample Input
11 5 7 9
1 2
1 3
1 4
2 3
1 4
Sample Output
11
HINT
Source
就是问你链上的最大异或... 最大异或一般用线性基来搞, 那么为了在树上快速合并线性基就用树上倍增来优化. 这样合并log次, 合并复杂度log^n, 则每次查询复杂度log^3n. (好像用分治可以降个log, 树上倍增当时拿不完分)
#include<bits/stdc++.h>
using namespace std;
typedef long long lnt;
const int P = 18;
const int maxn = 2e4 + 5;
int n, q, num;
lnt pw[62], val[maxn];
int h[maxn], dep[maxn], anc[maxn][P + 1];
inline const lnt read() {
register lnt x = 0;
register char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x;
}
struct edge { int nxt, v; }e[maxn * 2];
inline void add(int u, int v) {
e[++ num].v = v, e[num].nxt = h[u], h[u] = num;
e[++ num].v = u, e[num].nxt = h[v], h[v] = num;
}
struct Linear_basis { lnt b[62];}base[maxn][P + 1], ans;
inline void insert(Linear_basis &x, lnt y) {
for (int i = 60; ~i; -- i)
if (pw[i] & y) {
if (!x.b[i]) {
x.b[i] = y;
return;
} else y ^= x.b[i];
}
}
inline void merge(Linear_basis &x, Linear_basis y) {
for (int i = 60; ~i; -- i)
if (y.b[i]) insert(x, y.b[i]);
}
lnt query(int u, int v) {
if (dep[u] < dep[v]) swap(u, v);
int t = dep[u] - dep[v];
memset(ans.b, 0, sizeof(ans.b));
for (int i = 0; i <= P; ++ i)
if(t & pw[i])
merge(ans, base[u][i]), u = anc[u][i];
for (int i = P; ~i; -- i)
if (anc[u][i] != anc[v][i])
merge(ans, base[u][i]), merge(ans, base[v][i]),
u = anc[u][i], v = anc[v][i];
if (u != v) merge(ans, base[u][0]), u = anc[u][0], merge(ans, base[v][0]);
merge(ans, base[u][0]);
lnt tmp = 0;
for (int i = 61; ~i; -- i)
tmp = max(tmp, tmp ^ ans.b[i]);
return tmp;
}
void dfs(int u, int fa) {
insert(base[u][0], val[u]);
for (int i = 1; dep[u] >= pw[i]; ++ i) {
anc[u][i] = anc[anc[u][i - 1]][i - 1];
merge(base[u][i], base[u][i - 1]);
merge(base[u][i], base[anc[u][i - 1]][i - 1]);
}
for (int i = h[u]; i; i = e[i].nxt) {
int v = e[i].v;
if (v == fa) continue;
anc[v][0] = u;
dep[v] = dep[u] + 1, dfs(v, u);
}
}
int main() {
pw[0] = 1;
n = read(), q = read();
register int i;
for (i = 1; i <= 60; ++ i) pw[i] = pw[i - 1] << 1;
for (i = 1; i <= n; ++ i) val[i] = read();
int x, y;
for (i = 1; i < n; ++ i)
x = read(), y = read(), add(x, y);
dfs(1, 0);
for (i = 1; i <= q; ++ i) {
x = read(), y = read();
printf("%lld\n", query(x, y));
}
}
2423



被折叠的 条评论
为什么被折叠?



