/* 前向星 */ structEdge { int nxt, to, w; }; vector<Edge> E; int head[N], Log2[N], fa[88][N], dep[N], w[N];
inlinevoidadd(int u, int v, int w){ E.push_back({ head[u], v, w }); head[u] = E.size() - 1; }
voidinitlca(int u, int fau = 0){ dep[u] = dep[fau] + 1; fa[0][u] = fau; for (int i = 1; i <= Log2[dep[u]]; ++i) { fa[i][u] = fa[i - 1][fa[i - 1][u]]; } // u 的第 2^{i-1} 个父节点的第 2^{i-1} 个父节点即第 2^{i} 个父节点 for (int i = head[u]; i >= 1; i = E[i].nxt) { if (E[i].to != fau) { w[E[i].to] = E[i].w; // 将边权存储在子节点上 initlca(E[i].to, u); } } }
intgetlca(int u, int v){ if (dep[u] > dep[v]) std::swap(u, v); // -> dep[u]<=dep[v] while (dep[u] != dep[v]) v = fa[Log2[dep[v] - dep[u]]][v]; // -> dep[u]==dep[v] if (u == v) return u; for (int bit = Log2[dep[u]]; bit >= 0; --bit) { if (fa[bit][u] != fa[bit][v]) u = fa[bit][u], v = fa[bit][v]; } // 一步一步向上跳 return fa[0][u]; }
inlinevoidbeforeT(){ for (int i = 2; i < N; ++i) Log2[i] = Log2[i / 2] + 1; } // init Log2[]
structEdge { int nxt, to, w; }; vector<Edge> E; vector<pair<int, int> > Q[N]; int head[N], fa[N], vis[N], ans[N];
inlinevoidadd(int u, int v, int w){ E.push_back({ head[u], v, w }); head[u] = E.size() - 1; } // 前向星
inlinevoidinit(int n){ for (int i = 0; i <= n; ++i) fa[i] = i; } intfind(int x){ return fa[x] == x ? x : fa[x] = find(fa[x]); } inlinevoiduno(int x, int y){ fa[find(x)] = find(y); } // 并查集
voidtarjan(int u){ vis[u] = 1; // 访问过 但未回溯 即现在在访问它的子节点 for (int i = head[u]; i >= 1; i = E[i].nxt) { if (vis[E[i].to]) continue; tarjan(E[i].to); uno(E[i].to, u); } for (auto [v, id] : Q[u]) { if (vis[v] == 2) ans[id] = find(v); } vis[u] = 2; // 访问过 已回溯 它的子节点已经全部访问过 }
voideachT(){ E.push_back({ -1,0,0 }); for { add(u, v, 0); add(v, u, 0); } // 前向星存边 for (int i = 1; i <= q; ++i) { int u = read(), v = read(); if (u == v) ans[i] = u; // 特判 else Q[u].push_back({ v,i }), Q[v].push_back({ u,i }); } // 存储询问 init(n); // 并查集初始化 tarjan(st); // dfs for (int i = 1; i <= q; ++i) print(ans[i]); }
LCA 衍生
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// v 的 k 级祖先 intgetast(int v, int k){ k = dep[v] - k; // 期望的深度 if (k <= 0) return-1; // v 没有 k 级祖先 while (dep[v] < k) v = fa[Log2[k - dep[v]]][v]; return v; }
// fav 朝向 v 方向的儿子 intgetson(int fav, int v){ if (v == fav) return-1; // fav 与 v 相同 此函数无效 while (dep[fav] + 1 < dep[v]) v = fa[Log2[dep[v] - dep[fav] - 1]][v]; return v; }
/* 前向星和 LCA 略 */ int val[N]; inlinevoidinsert(int u, int v, int d = 1){ int Lca = getlca(u, v); val[u] += d; val[v] += d; val[Lca] -= d; val[fa[0][Lca]] -= d; }
voidgetsum(int u, int fau = 0){ for (int i = head[u]; i >= 1; i = E[i].nxt) { if (E[i].to != fau) { getsum(E[i].to, u); val[u] += val[E[i].to]; } } } // 差分的复原
voideachT(){ E.push_back({ -1,0,0 }); for { add(u, v, 0); add(v, u, 0); } // 前向星存边 initlca(rt); // LCA 初始化 rt 是树的根 for (int q = read(); q--;) insert(u, v, d); // 做差分 getsum(st); // 差分的复原 for (int i = 1; i <= n; ++i) print(val[i]); }