长链剖分O(nlogn)-O(1)求K级祖先
重链剖分是优先选最大的子树的根作为重儿子,而长链剖分是优先选最高的子树作为重儿子,然后把重儿子连成长链。
一个点到根的路径最多经过 \(O(\sqrt n)\) 条长链。
可以证明,长链剖分后,树上任意一个点 \(u\) 的 \(k\) 级祖先所在的长链长度一定 \(\geq k\)。
我们只需像倍增LCA一样先 \(O(n\log n)\) 预处理出倍增数组 \(anc\)。设 \(\mathrm{highbit}(x)\) 表示 \(x\) 的二进制最高位1的位数,例如 \(\mathrm{highbit}((1101)_2)=3\),那么我们预处理出 \(1\sim n\) 的 \(\mathrm{highbit}\)。
然后假设我们当前询问 \(u\) 的 \(k\) 级祖先,而 \(k=2^{\mathrm{highbit}(k)}+k-2^{\mathrm{highbit}(k)}\),我们先使用 \(anc\) 数组从 \(u\) 一步跳到它的 \(2^{\mathrm{highbit}(k)}\) 级祖先 \(v\),现在问题就转化成了求 \(v\) 的 \(k-2^{\mathrm{highbit}(k)}\) 级祖先。根据刚刚的结论,树上任意一个点 \(u\) 的 \(k\) 级祖先所在的长链长度一定 \(\geq k\),所以现在 \(v\) 所在的长链的长度一定 \(\geq 2^{\mathrm{highbit}(k)}\),而\(k-2^\mathrm{highbit(k)}<2^\mathrm{highbit(k)}\),所以我们只需在每条长链的链头建立两个大小都为长链的长度的桶,一个依次存储从链头向下的长链上的结点,一个依次存储从链头向上的结点,然后我们只需从 \(v\) 这个点由桶直接跳到 \(v\) 的 \(k-2^{\mathrm{highbit}(k)}\) 级祖先即可。预处理时间复杂度 \(O(n\log n)\),单次询问时间复杂度 \(O(1)\)。
Code
#include <bits/stdc++.h>
using namespace std;
#define RG register int
#define LL long long
template<typename elemType>
inline void Read(elemType& T) {
elemType X = 0, w = 0; char ch = 0;
while (!isdigit(ch)) { w |= ch == '-';ch = getchar(); }
while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
T = (w ? -X : X);
}
const int maxn = 300010;
struct Graph {
struct edge { int Next, to; };
edge G[maxn << 1];
int head[maxn];
int cnt;
Graph() :cnt(2) {}
void clear(int n) {
cnt = 2;fill(head, head + n + 2, 0);
}
void add_edge(int u, int v) {
G[cnt].to = v;
G[cnt].Next = head[u];
head[u] = cnt++;
}
};
Graph G;
int N, M;
int Deep[maxn], Height[maxn], Anc[maxn][20], Top[maxn], Hson[maxn];
int highbit[maxn], MaxDeep[maxn];
vector<int> Up[maxn], Down[maxn], Path;
void DFS1(int u, int fa) {
Anc[u][0] = fa;
Height[u] = 1;
for (int i = 1;i < 20;++i)
Anc[u][i] = Anc[Anc[u][i - 1]][i - 1];
for (int i = G.head[u];i;i = G.G[i].Next) {
int v = G.G[i].to;
if (v == fa) continue;
Deep[v] = Deep[u] + 1;
DFS1(v, u);
Height[u] = max(Height[u], Height[v] + 1);
if (Height[Hson[u]] < Height[v]) Hson[u] = v;
}
return;
}
void DFS2(int u, int fa, int top) {
Path.push_back(u);
Top[u] = top;
MaxDeep[top] = max(MaxDeep[top], Deep[u]);
Down[top].push_back(u);
if (Hson[u]) DFS2(Hson[u], u, top);
for (int i = G.head[u];i;i = G.G[i].Next) {
int v = G.G[i].to;
if (v == fa || v == Hson[u]) continue;
DFS2(v, u, v);
}
if (u == top) {
int len = MaxDeep[top] - Deep[u] + 1;
for (int i = Path.size() - 1;i >= max((int)Path.size() - len - 1, 0);--i)
Up[top].push_back(Path[i]);
}
Path.pop_back();
}
int KthAnc(int u, int k) {
if (k > Deep[u]) return 0;
if (k == 0) return u;
u = Anc[u][highbit[k]];
k -= (1 << highbit[k]);
if (Deep[u] - k == Deep[Top[u]]) return Top[u];
if (Deep[u] - k > Deep[Top[u]]) return Down[Top[u]][Deep[u] - k - Deep[Top[u]]];
return Up[Top[u]][Deep[Top[u]] - (Deep[u] - k)];
}
int main() {
Read(N);
for (int i = 1;i <= N - 1;++i) {
int u, v;
Read(u);Read(v);
G.add_edge(u, v);
G.add_edge(v, u);
}
DFS1(1, 0);
DFS2(1, 0, 1);
int Max = 1;
for (int i = 1;i <= N;++i) {
if ((i >> Max) & 1) ++Max;
highbit[i] = Max - 1;
}
Read(M);
int lastans = 0;
while (M--) {
int u, k;
Read(u);Read(k);
u ^= lastans;k ^= lastans;
lastans = KthAnc(u, k);
printf("%d\n", lastans);
}
return 0;
}