• 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;
    }
    
  • 相关阅读:
    flash 3d基础学习
    3d中的镜头
    [转]Android Canvas 切割 clipRect
    绘制球形
    绘制圆筒
    stage3d学习笔记1
    (转)Region.Op效果解析
    游戏中的镜头
    无向网的最小生成树——Prim算法(转)
    最短路径之——Dijkstra算法(转)
  • 原文地址:https://www.cnblogs.com/ftae/p/7236835.html
Copyright © 2020-2023  润新知