BZOJ 4568 [Scoi2016]幸运数字(树链剖分 + 异或线性基)
题目链接 BZOJ 4568
考虑树链剖分+线段树维护每一段区域的异或线性基
对于每个询问,求出该点集的异或线性基。然后求一下这个线性基里面能异或出的最大值即可。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define ls i << 1 #define rs i << 1 | 1 #define lson i << 1, L, mid #define rson i << 1 | 1, mid + 1, R typedef long long LL; const int N = 2e4 + 10; struct lb{ LL d[70]; int cnt; void clear(){ memset(d, 0, sizeof d); cnt = 0; } bool ins(LL val){ dec(i, 62, 0) if (val & (1LL << i)){ if (!d[i]){ d[i] = val; break; } val ^= d[i]; } return val > 0; } LL qmax(){ LL ret = 0; dec(i, 62, 0) if ((ret ^ d[i]) > ret) ret ^= d[i]; return ret; } LL qmin(){ rep(i, 0, 62) if (d[i]) return d[i]; return 0; } }; lb t[N << 3]; int f[N], fp[N], son[N], deep[N], father[N], sz[N], top[N]; int q, tot, n; LL a[N]; vector <int> v[N]; lb merge(const lb &n1, const lb &n2){ lb ret = n1; dec(i, 60, 0) if (n2.d[i]) ret.ins(n2.d[i]); return ret; } void dfs1(int x, int fa, int dep){ deep[x] = dep; father[x] = fa; son[x] = 0; sz[x] = 1; int ct = (int)v[x].size(); rep(i, 0, ct - 1){ int u = v[x][i]; if (u == fa) continue; dfs1(u, x, dep + 1); sz[x] += sz[u]; if (sz[son[x]] < sz[u]) son[x] = u; } } void dfs2(int x, int tp){ top[x] = tp; f[x] = ++tot; fp[f[x]] = x; if (son[x]) dfs2(son[x], tp); int ct = (int)v[x].size(); rep(i, 0, ct - 1){ int u = v[x][i]; if (u == father[x] || u == son[x]) continue; dfs2(u, u); } } void build(int i, int L, int R){ if (L == R){ t[i].ins(a[fp[L]]); return; } int mid = (L + R) >> 1; build(lson); build(rson); t[i] = merge(t[ls], t[rs]); } lb query(int i, int L, int R, int l, int r){ if (L == l && R == r) return t[i]; int mid = (L + R) >> 1; if (r <= mid) return query(lson, l, r); else if (l > mid) return query(rson, l, r); else return merge(query(lson, l, mid), query(rson, mid + 1, r)); } lb work(int x, int y){ lb ret; ret.clear(); int f1 = top[x], f2 = top[y]; for (; f1 != f2; ){ if (deep[f1] < deep[f2]) swap(f1, f2), swap(x, y); ret = merge(ret, query(1, 1, n, f[f1], f[x])); x = father[f1], f1 = top[x]; } if (x == y) return merge(ret, query(1, 1, n, f[x], f[y])); if (deep[x] > deep[y]) swap(x, y); return merge(ret, query(1, 1, n, f[x], f[y])); } int main(){ scanf("%d%d", &n, &q); rep(i, 1, n) scanf("%lld", a + i); rep(i, 2, n){ int x, y; scanf("%d%d", &x, &y); v[x].push_back(y); v[y].push_back(x); } dfs1(1, 0, 0); dfs2(1, 1); build(1, 1, n); while (q--){ int x, y; scanf("%d%d", &x, &y); lb cnt = work(x, y); printf("%lld\n", cnt.qmax()); } return 0; }