树链剖分求LCA(超级快)
学习树链剖分以后,可用于求LCA,居然比倍增大法快上一倍!!!

最后一发是树链剖分
老婆!!!tql,上模板题传送门
#include <bits/stdc++.h>
using namespace std;
template <typename T> inline void read(T& t)
{
int f = 0, c = getchar();
t = 0;
while (!isdigit(c)) f |= c == '-', c = getchar();
while (isdigit(c)) t = t * 10 + c - 48, c = getchar();
if (f) t = -t;
}
const int N = 5e5 + 10;
int cnt, head[N];
struct node
{
int to, nex;
} e[N << 1];
inline void add_edge(int u, int v)
{
e[++cnt].to = v;
e[cnt].nex = head[u];
head[u] = cnt;
}
int f[N], son[N], dep[N], siz[N], top[N];
//处理父亲 重儿子 深度
void dfs1(int u, int fa)
{
f[u] = fa, siz[u] = 1, dep[u] = dep[fa] + 1;
int mx = -1;
for(int i = head[u]; i; i = e[i].nex)
{
int v = e[i].to;
if(v == fa) continue;
dfs1(v, u);
siz[u] += siz[v];
if(siz[v] > mx)
{
mx = siz[v];
son[u] = v;
}
}
}
//树链剖分 处理top
void dfs2(int u, int t)
{
top[u] = t;
if(!son[u]) return; //没有重儿子代表是叶子节点
dfs2(son[u], t); //一直朝重儿子走 剖重链
for(int i = head[u]; i; i = e[i].nex)
{
int v = e[i].to;
if(v == f[u] || v == son[u]) continue;
dfs2(v, v); //另外开始一条链
}
}
//除根节点外任何一个结点的父亲节点一定在一条重链上
//因为父亲节点存在儿子 所以一定存在重儿子 一定在一条重链上
inline int lca(int u, int v)
{
while(top[u] != top[v]) //如果不在同一条重链上
{
//顶部节点深度较大得为u 一直往上跳
if(dep[top[u]] < dep[top[v]]) swap(u, v);
u = f[top[u]];
}
return dep[u] < dep[v] ? u : v;
}
int n, m, rt;
signed main()
{
read(n), read(m), read(rt);
int x, y;
for(int i = 1; i < n; ++i)
{
read(x), read(y);
add_edge(x, y);
add_edge(y, x);
}
dfs1(rt, rt);
dfs2(rt, rt);
while(m--)
{
read(x), read(y);
printf("%d\n", lca(x, y));
}
return 0;
}

浙公网安备 33010602011771号