[CF770C] Online Courses In BSU - LCA

有一棵 \(n\) 个节点的树,一共 \(q\) 次询问,每次询问给定 \(3\) 个点,求两条起点终点在这三个点上且不完全重合的路径的最多公共节点数。

Solution

枚举公共点,答案为 \((dis(a,b) + dis(a,c) - dis(b,c)) / 2 + 1\)

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 1000005;

int n,q,t1,t2,t3;
vector <int> g[N];
int dep[N],fa[N][20],vis[N];

void dfs(int p) {
    vis[p]=1;
    for(int q:g[p]) {
        if(vis[q]) continue;
        dep[q]=dep[p]+1;
        fa[q][0]=p;
        dfs(q);
    }
}

int lca(int p,int q) {
    if(dep[p]<dep[q]) swap(p,q);
    for(int i=18;i>=0;--i) if(dep[fa[p][i]]>=dep[q]) p=fa[p][i];
    for(int i=18;i>=0;--i) if(fa[p][i]-fa[q][i]) p=fa[p][i], q=fa[q][i];
    if(p-q) return fa[p][0];
    return p;
}

int dist(int p,int q) {
    int l=lca(p,q);
    return dep[p]+dep[q]-2*dep[l];
}

int calc(int a,int b,int c) {
    return (dist(a,b)+dist(a,c)-dist(b,c))/2;
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>n>>q;
    for(int i=1;i<n;i++) {
        cin>>t1;
        g[i+1].push_back(t1);
        g[t1].push_back(i+1);
    }
    dep[1]=1;
    dfs(1);
    for(int i=1;i<=18;i++) {
        for(int j=1;j<=n;j++) {
            fa[j][i]=fa[fa[j][i-1]][i-1];
        }
    }
    for(int i=1;i<=q;i++) {
        cin>>t1>>t2>>t3;
        cout<<max(max(calc(t1,t2,t3),calc(t2,t3,t1)),calc(t3,t1,t2))+1<<endl;
    }
}

上一篇:210. Course Schedule II


下一篇:超过5名学生的课