感觉题目都已经快把正解给说出来了...
strongly connected的两个点的消耗为0,其实就是同一个边双连通分量里面的点消耗为0。
然后缩一下点,再树形DP一下就完了。
第一次写边双,但感觉挺简单的。
#include#define ll long long using namespace std; const int N = 4e5 + 7; int c[N]; bool bridge[N * 2]; struct E { int v, ne; ll c; } e[N * 2], tree[N * 2]; int head[N], hd[N], cnt1, cnt2; int dfn[N], low[N], id; int color[N]; inline void add1(int u, int v, ll c) { e[++cnt1].v = v; e[cnt1].ne = head[u]; e[cnt1].c = c; head[u] = cnt1; } inline void add2(int u, int v, ll c) { tree[++cnt2].v = v; tree[cnt2].ne = hd[u]; tree[cnt2].c = c; hd[u] = cnt2; } void tarjan(int u, int edge) { dfn[u] = low[u] = ++id; for (int i = head[u]; i; i = e[i].ne) { int v = e[i].v; if (!dfn[v]) { tarjan(v, i); low[u] = min(low[u], low[v]); if (low[v] > low[u]) bridge[i] = bridge[i ^ 1] = 1; } else if (i != (edge ^ 1)) low[u] = min(low[u], dfn[v]); } } int dcc; void dfs0(int u) { c[u] = dcc; color[dcc] = min(color[dcc], u); for (int i = head[u]; i; i = e[i].ne) { int v = e[i].v; if (c[v] || bridge[i]) continue; dfs0(v); } } ll dp[N][2]; int son[N][2]; void dfs(int u, int fa) { dp[u][0] = dp[u][1] = 0; son[u][0] = son[u][1] = 0; for (int i = hd[u]; i; i = tree[i].ne) { int v = tree[i].v; if (v == fa) continue; dfs(v, u); if (dp[v][0] + tree[i].c > dp[u][0]) { dp[u][1] = dp[u][0]; son[u][1] = son[u][0]; dp[u][0] = dp[v][0] + tree[i].c; son[u][0] = v; } else if (dp[v][0] + tree[i].c > dp[u][1]) { son[u][1] = v; dp[u][1] = dp[v][0] + tree[i].c; } } } void dfs2(int u, int fa, ll c) { if (fa) { if (son[fa][0] != u) { if (dp[fa][0] + c > dp[u][0]) { dp[u][1] = dp[u][0]; son[u][1] = son[u][0]; dp[u][0] = dp[fa][0] + c; son[u][0] = fa; } else if (dp[fa][0] + c > dp[u][1]) { son[u][1] = fa; dp[u][1] = dp[fa][0] + c; } } else { if (dp[fa][1] + c > dp[u][0]) { dp[u][1] = dp[u][0]; son[u][1] = son[u][0]; dp[u][0] = dp[fa][1] + c; son[u][0] = fa; } else if (dp[fa][1] + c > dp[u][1]) { son[u][1] = fa; dp[u][1] = dp[fa][1] + c; } } } for (int i = hd[u]; i; i = tree[i].ne) { int v = tree[i].v; if (v == fa) continue; dfs2(v, u, tree[i].c); } } int main() { freopen("in.txt", "r", stdin); int T; scanf("%d", &T); while (T--) { int n, m; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { head[i] = hd[i] = 0; c[i] = 0; low[i] = dfn[i] = 0; color[i] = n + 1; } memset(bridge, 0, sizeof(bridge)); cnt1 = 1; for (int u, v, i = 1; i <= m; i++) { ll c; scanf("%d%d%lld", &u, &v, &c); add1(u, v, c); add1(v, u, c); } id = 0; for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i, 0); dcc = 0; for (int i = 1; i <= n; i++) if (!c[i]) { ++dcc; dfs0(i); } cnt2 = 1; for (int i = 2; i <= cnt1; i++) { int u = e[i ^ 1].v, v = e[i].v; if (c[u] == c[v]) continue; add2(c[u], c[v], e[i].c); } memset(dp, 0, sizeof(dp)); dfs(1, 0); dfs2(1, 0, 0); int ans1 = 0; ll ans2 = 1e18; for (int i = 1; i <= dcc; i++) { if (dp[i][0] < ans2) ans2 = dp[i][0], ans1 = color[i]; else if (dp[i][0] == ans2 && ans1 > color[i]) ans1 = color[i]; //printf("%lld\n", dp[i][0]); } printf("%d %lld\n", ans1, ans2); } return 0; }