Loading

[NOI2013] 快餐店

挺没意思的基环树好题。

首先定义基环树直径:\(\max dis(i, j)\),割掉环上的一条边可以产生一棵树,设这些树为 \(T_1, T_2, \dots, T_k\),那么直径就是 \(\min_i \max dis(T_i, u, v)\)\(dis(T_i, u, v)\) 表示第 \(i\) 棵树上 \(u, v\) 的距离。答案显然为直径长度除以 \(2\)

断环成链,类似 IOI Island 那题搞一下,要记 \(dp_u + sum_u\)\(dp_u - sum_u\) 的最大值,开个堆,由于这两个最大值取到的点可能是一样的,需要在这时考虑次大值的问题。

时间复杂度 \(\mathcal{O}(n \log n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int N = 1e6 + 10, mod = 998244353;
template<typename T>
void dbg(const T &t) { cout << t << endl; }
template<typename Type, typename... Types>
void dbg(const Type& arg, const Types&... args) {
    cout << arg << ' ';
    dbg(args...);
}
int n, dfn[N], idx, b[N], tot;
pii pre[N], cir[N];
ll dp[N], f[N], s[N], ans;
vector<pii>e[N];
struct cmp1 {
    bool operator()(int x, int y) {
        return f[x] - s[x] < f[y] - s[y];
    }
};
struct cmp2 {
    bool operator()(int x, int y) {
        return f[x] + s[x] < f[y] + s[y];
    }
};
#define y1 asfdasfasdf
priority_queue<int, vector<int>, cmp1>q1;
priority_queue<int, vector<int>, cmp2>q2;
inline void dfs(int u) {
    dfn[u] = ++idx;
    // dbg("###", u);
    for (auto [v, w] : e[u]) if (v != pre[u].first) {
        if (!dfn[v]) {
            pre[v] = {u, w};
            dfs(v);
        } else if (dfn[v] > dfn[u]) {
            cir[++tot] = {v, w};
            for (int x = v; ; x = pre[x].first) {
                cir[++tot] = {pre[x].first, pre[x].second};
                // dbg("###", u, v, x, pre[x].first);
                if (pre[x].first == u) {
                    break;
                }
            }
        }
    }
}
inline void dfs2(int u) {
    b[u] = 1;
    for (auto [v, w] : e[u]) if (!b[v]) {
        dfs2(v);
        ans = max(ans, dp[u] + dp[v] + w);
        dp[u] = max(dp[u], dp[v] + w);
    }
}
int main() {
    // freopen("data.in", "r", stdin);
    // freopen("data.out", "w", stdout);
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n;
    for (int i = 1, u, v, w; i <= n; i++) {
        cin >> u >> v >> w;
        e[u].push_back({v, w}); e[v].push_back({u, w});
    }
    dfs(1);
    for (int i = 1; i <= tot; i++) b[cir[i].first] = 1;
    for (int i = 1; i <= tot; i++) dfs2(cir[i].first);
    for (int i = tot + 1; i <= tot + tot; i++) cir[i] = cir[i - tot];
    for (int i = 1; i <= tot + tot; i++) s[i] = s[i - 1] + cir[i].second, f[i] = dp[cir[i].first];
    for (int i = 1; i <= tot; i++) q1.push(i), q2.push(i);
    ll res = 1ll << 60;
    for (int i = 1; i <= tot; i++) {
        while (!q1.empty() && q1.top() < i) q1.pop();
        while (!q2.empty() && q2.top() < i) q2.pop();
        int x = q1.top(), y = q2.top();
        if (x == y) {
            q1.pop(); q2.pop();
            while (!q1.empty() && q1.top() < i) q1.pop();
            while (!q2.empty() && q2.top() < i) q2.pop();
            if (q1.empty()) continue;
            int x1 = q1.top(), y1 = q2.top(); 
            res = min(res, max(f[x1] - s[x1] + f[y] + s[y], f[x] - s[x] + f[y1] + s[y1]));
            q1.push(x), q2.push(y);
        } else res = min(res, f[x] - s[x] + f[y] + s[y]);
        q1.push(i + tot); q2.push(i + tot);
    }
    ans = max(ans, res);
    cout << ans / 2 << (ans & 1 ? ".5\n" : ".0\n");
    return 0;
}

posted @ 2025-12-25 09:09  循环一号  阅读(1)  评论(0)    收藏  举报