题意: https://loj.ac/problem/2013
sol:
用点分治每次处理lca在分治重心上的询问,对于每个询问都单独开个表挂在其中一个点上
树剖和倍增都是3个log,需要卡常(其实是复杂度不对),点分治处理路径是$\log w \log n$,然后每个点上的询问会被搞q次
如果回答询问的话是$\log w^2$的复杂度,总复杂度$n \log n\log w+q\log w^2$
点分代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
const int N = 2e4+7;
typedef long long LL;
#define R register
#define debug printf("GG\n")
#define cer(x) printf("%d\n", x)
int last[N], cnt;
std :: vector<int> G[N], Q[N];
inline int max(int a, int b) {
return a > b ? a : b;
}
struct Edge {
int to, nxt;
} e[N*2];
inline void add(int u, int v) {
e[++cnt].nxt = last[u], e[cnt].to = v, last[u] = cnt;
}
LL pw[N];
struct Ask {
int x, y;
LL ans;
} q[N*10];
struct LB {
LL d[62];
inline void ins(LL x) {
for (R int i = 60; i >= 0; i--) if ((x >> i) & 1) {
if (!d[i]) {
d[i] = x;
break;
} else x ^= d[i];
}
}
inline LL query() {
LL res = 0;
for (R int i = 60; i >= 0; i--)
((res ^ d[i]) > res) ? res ^= d[i] : 0;
return res;
}
void clear() {
memset(d, 0, sizeof(d));
}
};
LB B[N];
int siz[N], rt, SIZ, vis[N], mxson[N];
void findrt(int x, int fa) {
siz[x] = 1, mxson[x] = 0;
//cer(x);
for (int o = last[x]; o; o = e[o].nxt) {
int to = e[o].to;
if (to == fa || vis[to]) continue;
findrt(to, x), siz[x] += siz[to], mxson[x] = max(mxson[x], siz[to]);
}
mxson[x] = max(mxson[x], SIZ - siz[x]);
mxson[x] < mxson[rt] ? rt = x : 0;
//debug;
}
int vis2[N], q1[N], tail, front, solved[N*10], col[N];
void findp(int x, int fa, int color) {
//if (!fa && B[fa].query() > 0) debug;
B[x] = B[fa], B[x].ins(pw[x]), vis2[x] = 1;
q1[tail++] = x, col[x] = color;
//cer(x);
for (R int o = last[x]; o; o = e[o].nxt) {
int to = e[o].to;
if (to == fa || vis[to]) continue;
findp(to, x, !fa ? ++color : color);
}
}
int q2[N], t2, f2;
void getans(int x) {
tail = front = t2 = f2 = 0; findp(x, 0, 0);
while (front < tail) {
int nx = q1[front++], size = G[nx].size();
for (R int o = 0; o < size; o++)
if (vis2[G[nx][o]] && !solved[Q[nx][o]] && (col[nx] != col[G[nx][o]] || (nx == x && G[nx][o] == x))) {
LB res = B[nx];
for (R int i = 60; i >= 0; i--)
if (B[G[nx][o]].d[i] > 0) res.ins(B[G[nx][o]].d[i]);
solved[Q[nx][o]] = 1;
q[Q[nx][o]].ans = res.query();
//if (x == 1) cer(B[nx].query());
}
q2[t2++] = nx;
}
while (f2 < t2) {
B[q2[f2]].clear(); vis2[q2[f2]] = col[q2[f2]] = 0; f2++;
} B[0].clear();
}
void divrt(int x) {
vis[x] = 1; getans(x);
for (R int o = last[x]; o; o = e[o].nxt) {
int to = e[o].to;
if (vis[to]) continue;
rt = 0, SIZ = siz[to], findrt(to, x), divrt(rt);
}
}
int n, qq;
int main() {
//freopen("pick.in", "r", stdin);
//freopen("pick_check.out", "w", stdout);
scanf("%d%d", &n, &qq);
for (R int i = 1; i <= n; i++)
scanf("%lld", &pw[i]);
for (R int i = 1, x, y; i < n; i++)
scanf("%d%d", &x, &y), add(x, y), add(y, x);
for (R int i = 1; i <= qq; i++)
scanf("%d%d", &q[i].x, &q[i].y), G[q[i].x].push_back(q[i].y), Q[q[i].x].push_back(i);
siz[0] = mxson[0] = SIZ = n, rt = 0;
findrt(1, 0), divrt(rt);
//cer(rt);
for (R int i = 1; i <= qq; i++)
printf("%lld\n", q[i].ans);
return 0;
}
树剖代码:
卡过去其实挺简单?在线性基里维护一个minmax然后扫的时候只扫minmax就好了大概常数能减小一半
#include<cstdio>
#include<iostream>
#include<cstring>
#define R register
#define debug printf("GG\n")
const int N = 2e5+7;
typedef long long LL;
int last[N], cnt;
struct Edge {int to, nxt;} e[N*2];
int n, q; LL val[N];
inline int min(R int a, R int b) {
return b > a ? a : b;
}
inline int max(R int a, R int b) {
return a > b ? a : b;
}
inline void add(R int u, R int v) {
e[++cnt].nxt = last[u], e[cnt].to = v, last[u] = cnt;
}
struct LB {
LL d[61]; int Last, Start;
inline void Modify(R LL x) {
for (R int i = 60; i >= 0; i--)
if ((x >> i) & 1LL) {
if (!d[i]) {
d[i] = x;
Start = max(Start, i);
Last = min(Last, i);
break;
}
else x ^= d[i];
} else if (!x) break;
}
inline void clear() {
memset(d, 0, sizeof(d));
}
};
struct Graph {
int dep, fa, siz, son, top;
LL w;
} G[N];
void dfs1(int x, int fa, int dep) {
G[x].siz = 1, G[x].dep = dep, G[x].fa = fa;
G[x].w = val[x];
// if (x == 2)
// printf("%d %d %d\n", x, G[x].dep, G[x].fa);
int max_son = -1;
for (int o = last[x]; o > 0; o = e[o].nxt) {
//debug;
//printf("%d %d\n", o, e[o].to);
int to = e[o].to;
//printf("%d ", to);
// if (to == 2)
// printf("%d %d %d\n", x, G[x].dep, G[x].fa);
if (to == fa) continue;
dfs1(to, x, dep + 1);
G[x].siz += G[to].siz;
if (G[to].siz > max_son)
max_son = G[to].siz, G[x].son = to;
}
}
int idx[N];LL A[N];
void dfs2(int x, int top) {
G[x].top = top, idx[x] = ++cnt, A[cnt] = G[x].w;
if (!G[x].son) return;
dfs2(G[x].son, top);
for (int o = last[x]; o > 0; o = e[o].nxt) {
int to = e[o].to;
//debug;
if (to == G[x].fa || to == G[x].son) continue;
dfs2(to, to);
}
}
struct segT {
int lc, rc; LB omg;
} t[N*2];
inline void pushup(R int u) {
LB A = t[t[u].lc].omg, B = t[t[u].rc].omg;
for (R int i = B.Start; i >= B.Last; i--)
if (B.d[i] > 0) A.Modify(B.d[i]);
t[u].omg = A;
}
void build(int u, int l, int r) {
//int MID = (l + r) >> 1;
if (l == r) {
t[u].omg.Modify(A[l]); return;
}
int MID = (l + r) >> 1;
build(t[u].lc = ++cnt, l, MID),
build(t[u].rc = ++cnt, MID + 1, r);
pushup(u);
}
LB res;
void query(int u, int l, int r, int sl, int sr) {
if (sl == l && sr == r) {
LB A = t[u].omg;
for (R int i = A.Start; i >= A.Last; i--)
if (A.d[i] > 0) res.Modify(A.d[i]);//, printf("%d %d %d\n", i, A.d[i], l);
return;
}
int MID = (l + r) >> 1;
if (sr <= MID) query(t[u].lc, l, MID, sl, sr);
else if (sl > MID) query(t[u].rc, MID + 1, r, sl, sr);
else query(t[u].lc, l, MID, sl, MID), query(t[u].rc, MID + 1, r, MID + 1, sr);
}
inline LL ASK(R int x, R int y) {
//LB ans; ans.clear();
//debug;
res.clear();
while (G[x].top != G[y].top) {
//res.clear();
// printf("%d %d %d %d\n", x, G[x].top, y, G[y].top);
if (G[G[x].top].dep < G[G[y].top].dep)
std :: swap(x, y);
query(1, 1, n, idx[G[x].top], idx[x]);
x = G[G[x].top].fa;
// for (int i = 60; i >= 0; i--)
// if (res.d[i] > 0) ans.Modify(res.d[i]);
}
if (G[x].dep < G[y].dep) std :: swap(x, y);
//res.clear();
query(1, 1, n, idx[y], idx[x]);
//for (int i = 60; i >= 0; i--)
// if (res.d[i] > 0) ans.Modify(res.d[i]);
R LL ii = 0LL;
for (R int i = res.Start; i >= res.Last; i--)
if (res.d[i] > 0)
ii = (ii ^ res.d[i]) > ii ? (ii ^ res.d[i]) : ii;
return ii;
}
int main() {
scanf("%d%d", &n, &q);
for (R int i = 1; i <= n; i++)
scanf("%lld", &val[i]);
for (R int i = 1, ox, oy; i < n; i++) {
R int x, y;
scanf("%d%d", &x, &y), add(x, y), add(y, x);
}
//for (int i = 1; i <= 2 * n - 2; i++)
// printf("last : %d to : %d nxt : %d x : %d\n", last[i], e[i].to, e[i].nxt, i);
dfs1(1, 1, 1), cnt = 0, dfs2(1, 1), cnt = 1, build(1, 1, n);
while (q--) {
R int x, y;
scanf("%d%d", &x, &y);
printf("%lld\n", ASK(x, y));
}
}