1. 程式人生 > >luogu3761 [TJOI2017]城市

luogu3761 [TJOI2017]城市

== sca AR truct num sizeof 找到 ron pop

題目

  luogu3761

題解

  顯然,只有在原樹直徑上刪邊,才可能使新樹的直徑變小,於是枚舉直徑上每條邊

  算了直徑復雜度也是O(n)級的,幹脆直接暴力枚舉所有的邊

  刪邊後原樹被分成 l, r 兩顆子樹,組成的新樹直徑有三種可能

  1. 新樹的直徑為子樹 l 的直徑

  2. 新樹的直徑為子樹 r 的直徑

  3. 設新連的邊的兩端點分別為 lx, rx,dis(lx/rx) 分別為 lx/rx 到子樹 l/r 最遠點的距離,新樹的直徑為 dis(lx) + dis(rx) + w(刪除邊的邊權)

  新樹的直徑即為三種情況取 max

  子樹 l, r 的直徑可以兩邊bfs求得,就不多加闡述了

  對於第三種情況,首先要找到連新邊的端點 lx, rx

  顯然,要使 lx 到最遠點的距離最短,lx 必然在樹 l 的直徑上,由反證法可得

  暴力枚舉直徑上所有點

代碼

  

#include <bits/stdc++.h>
using namespace std;
const int N = 5005;
const int inf = 1e9;

int n;

struct node
{
    int fr, to, w, nt;
    node(int ff = 0, int tt = 0, int ww = 0, int nn = 0) {fr = ff; to = tt; w = ww; nt = nn;}
}E[N * 2];
int num, p[N];

void add(int x, int y, int z) {E[++num] = node(x, y, z, p[x]); p[x] = num;}

int dis[N], fr[N], v[N]; queue<int> q;
void bfs(int s, int bre)
{
    memset(dis, -1, sizeof(dis));
    dis[s] = 0; q.push(s);
    while (!q.empty())
    {
        int x = q.front(); q.pop();
        for (int e = p[x]; e; e = E[e].nt)
        {
            if (e == bre || e == bre + 1) continue;
            int k = E[e].to;
            if (dis[k] == -1)
            {
                dis[k] = dis[x] + E[e].w;
                fr[k] = x; v[k] = E[e].w;
                q.push(k);
            }
        }
    }
}

int deal(int id)
{
    int x[2]; x[0] = E[id].fr, x[1] = E[id].to;
    int d[2] = {0, 0}, s[2] = {0, 0}, t[2] = {0, 0}, r[2] = {0, 0};
    for (int k = 0; k < 2; k++)
    {
        bfs(x[k], id);
        for (int i = 1; i <= n; i++) if(dis[i] > dis[s[k]]) s[k] = i;
        bfs(s[k], id);
        for (int i = 1; i <= n; i++) if(dis[i] > dis[t[k]]) t[k] = i; d[k] = dis[t[k]];
        if(t[k] == s[k]) r[k] = 0;
        else
        {
            int cnt = 0; r[k] = inf;
            while (t[k] != s[k])
            {
                cnt += v[t[k]];
                r[k] = min(r[k], max(d[k] - cnt, cnt));
                t[k] = fr[t[k]];
            }
        }
    }
    return max(r[0] + r[1] + E[id].w, max(d[0], d[1]));
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i < n; i++)
    {
        int x, y, z; scanf("%d%d%d", &x, &y, &z);
        add(x, y, z); add(y, x, z);
    }
    int ans = inf;
    for (int i = 1; i <= num; i += 2) ans = min(ans, deal(i));
    cout << ans;
    return 0;
}

luogu3761 [TJOI2017]城市