Codeforces Round #425 (Div. 2)D. Misha, Grisha and Underground(LCA)

題目鏈接

http://codeforces.com/contest/832/problem/D

題目大意

給你一棵樹, 以及q次詢問,每次詢問給你a,b, c三個節點
你可以將這三個節點任意(一一對應)定爲s, f, t節點,
然後進行以下操作
從s–>f跑最短路,並標記路上的點
從t–>f跑最短路,統計剛剛標記的點的個數
(每次詢問過後標記的點會被清空)
問你每次詢問統計出的標記的點個數的最大值

思路

樹上最短路我們可以用LCA(兩個節點最近的公共祖先)進行計算

我們用ab表示lca(a, b), ac = lca(a, c), bc = lca(b, c)
這樣必定會有兩個值相等, 如下圖所示
這裏寫圖片描述

那麼最大值必然在三條路之間
a–>ab
b–>ab
c–>ab
至於路徑的計算,lca計算過程中有一個deep數組,用於記錄節點所在深度,那麼a–>ab距離 = deep[a] - deep[ab], 以此類推

代碼

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

const int M = 1e5 + 5;

vector<int>g[M];
int root;
int parent[20][M];
int dep[M];
int n, q;

void dfs(int v, int p, int d)
{
    parent[0][v] = p;
    dep[v] = d;
    for(int i=0; i<g[v].size(); ++i)
    {
        if(g[v][i]!=p) dfs(g[v][i], v, d+1);
    }
}

void init()
{
    for(int k = 0; k < 20-1; ++ k)
    {
        for(int v = 1; v <= n; ++ v)
        {
            if(parent[k][v] < 0) parent[k+1][v] = -1;
            else
            {
                parent[k+1][v] = parent[k][parent[k][v]];
            }
        }
    }
}

int getlca(int u, int v)
{
    if(dep[u] > dep[v]) swap(u, v);
    int ans = 0;
    for(int k = 0; k < 20; ++ k)
    {
        if((dep[v] - dep[u]) >> k & 1)
        {
            v = parent[k][v];
        }
    }
    if(u != v)
    {
        for(int k = 20 - 1; k >= 0; -- k)
        {
            if(parent[k][u] != parent[k][v])
            {
                u = parent[k][u], v = parent[k][v];
            }
        }
        u = parent[0][u];
        return u;
    }
    return u;
}

int solve(int a, int b, int c, int ab, int ac)
{
    int mx = 0;
    mx = max(dep[a] - dep[ab] + 1, dep[b] - dep[ab] + 1);
    mx = max(mx, dep[ab] - dep[ac] + dep[c] - dep[ac] + 1);
    return mx;
}

int main()
{
    scanf("%d%d", &n, &q);
    for(int i=1; i<n; ++i)
    {
        int tmp;
        scanf("%d", &tmp);
        g[i+1].push_back(tmp);
        g[tmp].push_back(i+1);
    }
    dfs(1, -1, 1);
    init();
    for(int i=0; i<q; ++i)
    {
        int a, b, c, ans = 0;
        scanf("%d%d%d", &a, &b, &c);
        int ab = getlca(a, b);
        int bc = getlca(b, c);
        int ac = getlca(a, c);
        int mx = max(dep[ab], max(dep[bc], dep[ac]));
        if(dep[ab] == mx)
        {
            ans = solve(a, b, c, ab, ac);
        }
        else if(dep[ac] == mx)
        {
            ans = solve(a, c, b, ac, ab);
        }
        else if(dep[bc] == mx)
        {
            ans = solve(b, c, a, bc, ab);
        }
        printf("%d\n", ans);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章