본문으로 건너뛰기
목차18
Notes
18

LCA

트리의 최소 공통 조상

int N, Q, D[101010], P[22][101010];
ll Dist[101010];
vector<pair<int,int>> G[101010]; // {정점, 가중치}
void Connect(int u, int v, int w=1){
    G[u].push_back({v, w}); G[v].push_back({u, w});
}
void DFS(int v, int b=-1){
    for(auto [i, w] : G[v]) if(i != b){
        D[i] = D[v] + 1; Dist[i] = Dist[v] + w; P[0][i] = v;
        DFS(i, v);
    }
}
int LCA(int u, int v){
    if(D[u] < D[v]) swap(u, v);
    int diff = D[u] - D[v];
    for(int i=0; diff; i++, diff>>=1) if(diff & 1) u = P[i][u];
    if(u == v) return u;
    for(int i=21; i>=0; i--) if(P[i][u] != P[i][v]) u = P[i][u], v = P[i][v];
    return P[0][u];
}
int Kth(int v, int k){ // v에서 k번 부모로 올라간 정점
    for(int i=0; k; i++, k>>=1) if(k & 1) v = P[i][v];
    return v;
}
ll Distance(int u, int v){ // u-v 경로의 가중치 합 (가중치 안 주면 간선 수)
    int l = LCA(u, v);
    return Dist[u] + Dist[v] - 2 * Dist[l];
}
int KthOnPath(int u, int v, int k){ // u-v 경로에서 u로부터 k번째 정점 (0-indexed, u가 0번째)
    int l = LCA(u, v);
    int du = D[u] - D[l];
    if(k <= du) return Kth(u, k);
    int dv = D[v] - D[l];
    return Kth(v, du + dv - k);
}
////
// 1. Connect(u, v[, w])로 간선 추가 (가중치 없으면 w 생략, 기본값 1)
// 2. DFS(1) 호출
// 3. 아래 코드 실행
for(int i=1; i<22; i++) for(int j=1; j<=N; j++) P[i][j] = P[i-1][P[i-1][j]];
// 4. LCA(u, v)로 최소 공통 조상
// 5. Distance(u, v)로 두 정점 사이 거리
// 6. KthOnPath(u, v, k)로 u-v 경로에서 u로부터 k번째 정점