[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;
}

浙公网安备 33010602011771号