P10113 大量的工作沟通
题意:
求出m个节点的最近公共祖先,输出 $ 根 → 最近公共祖先$ 路径上的最大编号

思路:
-
多叉树的lca
-
0号-根
\(i\)的父亲是\(f_i\),建立一条\(f_i->i\)和\(i->f_i\)的边
-
针对每次合作,有m个员工
找到这m个员工的lca(暴力求可以过)
取\(0-lca\)的链上编号的max
优化:
- 预处理出\(root-i\)路径上编号的max
图解:

代码:
const int N=1e5+5;
const int K=20;
int n,q,m;
int fa[N][21],depth[N],mx[N];//mx[i]:root-i的最大编号
vector<int> e[N];
vector<int> a;
void dfs1(int x,int f,int lst_mx)
{
fa[x][0]=f;depth[x]=depth[f]+1;
for(int i=1;i<=K;++i){
fa[x][i]=fa[fa[x][i-1]][i-1];
}
mx[x]=max(lst_mx,x);
for(int v:e[x]){
if(v==f) continue;
dfs1(v,x,mx[x]);
}
}
int LCA(int x,int y)
{
if(depth[x]<depth[y]) swap(x,y);
for(int i=K;i>=0;--i){
if(depth[fa[x][i]]>=depth[y]){
x=fa[x][i];
}
}
if(x==y) return x;
for(int i=K;i>=0;--i){
if(fa[x][i]!=fa[y][i]){
x=fa[x][i];
y=fa[y][i];
}
}
return fa[x][0];
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
int fi;
cin>>n;
for(int i=1;i<n;++i){
cin>>fi;
e[i].push_back(fi);
e[fi].push_back(i);
}
dfs1(0,0,0);
cin>>q;
while(q--){
cin>>m;
a.clear();a.resize(m);
for(int i=0;i<m;++i){
cin>>a[i];
}
//求出a[0]-a[m-1]的lca
int tmp=LCA(a[0],a[1]);
for(int i=2;i<m;++i){
tmp=LCA(tmp,a[i]);
}
//求出root-lca(a[0]-a[m-1])编号max
cout<<mx[tmp]<<"\n";
}
return 0;
}

浙公网安备 33010602011771号