【CF1294F】Three Paths on a Tree


Description

給出一棵無權樹(可理解為邊權為 \(1\))。

你需要選取三個點 \(a,b,c\),最大化 \(a,b\)\(b,c\)\(a,c\) 的簡單路徑的並集的長度。

輸出這個最大長度和 \(a,b,c\)

Solution

有一個結論:

必定會存在一組最優解,使得 \(a,b\) 是樹直徑上的端點。

那我們可以套路地去把樹直徑兩端點求出來,推薦大家用兩次搜索求出樹直徑端點。

確定了 \(a,b\),接下來我們只要去找到最優的 \(c\),就可以最大化答案了。

此時我們注意到:\(a,b\)\(b,c\)\(a,c\) 的簡單路徑的並集的長度其實就是 \(\frac{\text{dist}(a,b)+\text{dist}(b,c)+\text{dist}(a,c)}{2}\)

此時 \(\text{dist}(a,b)\) 已經確定了,當 \(\text{dist}(b,c)+\text{dist}(a,c)\) 的值取到最大,那么整個式子取最大。

\(a,b\) 到所有點的簡單路徑距離求出來,去枚舉這個最優的 \(c\) 即可,枚舉的過程中記得判與 \(a,b\) 相同的情況。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

#define RI register int

using namespace std;

inline int read() {
    int x = 0, f = 1;
    char s = getchar();

    while (s < '0' || s > '9') {
        if (s == '-')
            f = -f;

        s = getchar();
    }

    while (s >= '0' && s <= '9') {
        x = x * 10 + s - '0';
        s = getchar();
    }

    return x * f;
}

const int N = 200100, M = 400100;

int n;

int tot, head[N], ver[M], edge[M], Next[M];

void add(int u, int v, int w) {
    ver[++tot] = v;
    edge[tot] = w;
    Next[tot] = head[u];
    head[u] = tot;
}

int d[N], vis[N];

int pos;

void bfs(int sta) {
    memset(d, 0, sizeof(d));
    memset(vis, 0, sizeof(vis));

    queue<int>q;

    q.push(sta);
    vis[sta] = 1;

    while (q.size()) {
        int u = q.front();
        q.pop();

        for (RI i = head[u]; i; i = Next[i]) {
            int v = ver[i], w = edge[i];

            if (vis[v])
                continue;

            d[v] = d[u] + w;
            vis[v] = 1;

            if (d[v] > d[pos])
                pos = v;

            q.push(v);
        }
    }
}

int p1, p2;
int ans;

int tmp1[N], tmp2[N];

int main() {
    n = read();

    for (RI i = 1; i < n; i++) {
        int u = read(), v = read();
        add(u, v, 1), add(v, u, 1);
    }

    bfs(1);
    p1 = pos;

    bfs(p1);
    p2 = pos;

    for (RI i = 1; i <= n; i++)
        tmp1[i] = d[i];

    bfs(p2);

    for (RI i = 1; i <= n; i++)
        tmp2[i] = d[i];

    pos = 0;

    for (RI i = 1; i <= n; i++)
        if (tmp1[i] + tmp2[i] > tmp1[pos] + tmp2[pos] && i != p1 && i != p2)
            pos = i;

    ans = (tmp1[p2] + tmp1[pos] + tmp2[pos]) / 2;

    printf("%d\n", ans);
    printf("%d %d %d\n", p1, p2, pos);

    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM