Codeforces #425 Div2 D

#425 Div2 D

题意

给出一个树形图,每次询问给出三个点,从其中选择两个作为起始点,一个终点,求从两个起始点出发(走最短路)到达终点经过的共同的点最多的数量。

分析

这种树上点与点之间距离有关的问题大多与 LCA 有关,那么我暴力枚举每个点分别作为起始点、终点,求下最大距离就好了。

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 10;
const int LOG_N = 18;
int n;
int dep[MAXN];
int par[MAXN][20];
vector<int> G[MAXN];
void dfs(int fa, int u, int d) {
    par[u][0] = fa;
    dep[u] = d;
    for(int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        if(v != fa) {
            dfs(u,v, d + 1);
        }
    }
}
void init() {
    for(int i = 1; (1 << i) < MAXN; i++) {
        for(int j = 1; j <= n; j++) {
            if(par[j][i - 1] == -1) par[j][i - 1] = -1;
            else par[j][i] = par[par[j][i - 1]][i - 1];
        }
    }
}
int lca(int u, int v) {
    if(dep[u] > dep[v]) swap(u, v);
    for(int i = 0; (1 << i) < MAXN; i++) {
        if((dep[v] - dep[u]) >> i & 1) {
            v = par[v][i];
        }
    }
    if(v == u) return u;
    for(int i = LOG_N; i >= 0; i--) {
        if(par[u][i] != par[v][i]) {
            u = par[u][i];
            v = par[v][i];
        }
    }
    return par[u][0];
}
int query(int u, int v) {
    int w = lca(u, v);
    return dep[u] + dep[v] - 2 * dep[w];
}
int main() {
    int q;
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> q;
    for(int i = 2; i <= n; i++) {
        int x;
        cin >> x;
        G[i].push_back(x);
        G[x].push_back(i);
    }
    dfs(-1, 1, 0);
    init();
    while(q--) {
        int a[3];
        for(int i = 0; i < 3; i++) cin >> a[i];
        int ans = 0;
        sort(a, a + 3);
        do {
            int s = a[0], t = a[1], f = a[2];
            if(s == t) ans = max(ans, query(s, f));
            else {
                int w = lca(s, t), w1 = lca(s, f), w2 = lca(t, f);
                if(dep[w1] > dep[w2]) { swap(s, t); swap(w1, w2); }
                if(lca(f, w1) == lca(w1, w2)) { // f w1 w2 在一条链上
                    ans = max(ans, query(w2, f));
                }
                if(w1 == w2) {
                    ans = max(ans, query(w, f));
                }
            }
        }while(next_permutation(a, a + 3));
        cout << ans + 1 << endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ftae/p/7236835.html