题意: 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)); } }