树链剖分
原理
树链剖分是根据轻重儿子,将一棵树剖成多条链,然后就可以用数据结构来维护这些链了,听着似乎还是有点像暴力,不过因为一条链有多个结点,所以可以优化时间复杂度。
树上LCA2
给你一棵 n 个节点的以 11 号节点为根的树,节点的编号为 1 到 n。现在有 m 组询问,对于每组询问 u,v,请求出 u 号节点和 v 号节点的最近公共祖先。
输入格式
第一行一个整数 n 表示节点数。
接下来 n−1 行,每行两个整数 x,y表示 x 号节点和 y 号节点之间有一条边。
输入保证是一棵树。
接下来一行一个整数 m 表示询问数。
接下来 m 行,每行两个整数 u,v表示一组询问。
输出格式
输出共 m 行,对于每组询问,输出一行一个整数表示对应的两个点的最近公共祖先的编号。
样例输入
4
1 2
1 3
3 4
2
1 2
2 4
样例输出
1
1
数据规模
对于所有数据,保证 1≤n,m≤100000,1≤u,v≤n。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n,m,tot;
int l[N],dep[N],fa[N],top[N],sz[N],hs[N],id[N];
vector<int>e[N];
void dfs1(int u,int v)
{
sz[u] = 1;
hs[u] = -1;
dep[u] = dep[v] + 1;
fa[u] = v;
for(auto c:e[u])
{
if(c == v)
continue;
dfs1(c,u);
sz[u] += sz[c];
if(sz[c] > sz[hs[u]])
hs[u] = c;
}
}
void dfs2(int u,int v)
{
top[u] = v;
l[u] = ++tot;
id[tot] = u;
if(hs[u] != -1)
dfs2(hs[u],v);
for(auto c:e[u])
{
if(hs[u]!=c&&fa[u]!=c)
dfs2(c,c);
}
}
int lca(int u,int v)
{
while(top[u] != top[v])
{
if(dep[top[u]] < dep[top[v]])
{
v = fa[top[v]];
}
else
u = fa[top[u]];
}
if(dep[u] < dep[v])
return u;
else
return v;
}
int main()
{
cin >> n;
for(int i = 1;i < n;i ++)
{
int x,y;
cin >> x >> y;
e[x].push_back(y);
e[y].push_back(x);
}
dfs1(1,0);
dfs2(1,1);
cin >> m;
for(int i = 1;i <= m;i ++)
{
int x,y;
cin >> x >> y;
cout << lca(x,y) << '\n';
}
}