好吧我的本意是想学习一下dp的。然后发现了这道纠结了一年半还多的题。
首先把环找出来。然后环上会长一些树。先把树的答案求了,因为它很好求。
然后考虑环,那么答案应该是随便断一条边之后答案的最小值(而不是最大值)。于是乎记录一下每个点按某个方向到起点的距离,记为d[i]。算一下每个点的树的深度,记为l[i]。于是每次要最大化l[i]+l[j]+|d[i]-d[j]|。反正是最大化所以顺序是没有关系的,但是不能自交。这是个比较容易错的地方。于是就去写个线段树来维护吧。只查询不修改让我总有能线性搞的想法,虽然没想清楚具体怎么实现。
#include <cstdio> #include <cstring> #include <algorithm> #include <set> using namespace std; struct edge { int t, v; edge *next; }; typedef long long dint; #ifdef WIN32 #define lld "%I64d" #else #define lld "%lld" #endif #define _l (long long int) const int maxn = 100009; edge elst[maxn << 1], *ep(elst), *head[maxn]; int n, fa[maxn], df[maxn], ol[maxn], d[maxn]; int tlp, lp[maxn << 1]; dint lv[maxn << 1], le[maxn << 1], md[maxn], ans; inline void addEdge(int u, int v, int w) { ep-> t = v; ep-> v = w; ep-> next = head[u]; head[u] = ep ++; } void findLoop() { static int q[maxn]; int hd(0), tl(1); int uo(0), vo(0), dx, a; q[0] = 1; fa[1] = -1; d[1] = 1; memset(ol, 0, sizeof(ol)); memset(fa, 0, sizeof(fa)); while (hd < tl && !uo) { int p(q[hd ++]); for (edge* e = head[p]; e; e = e-> next) if (e-> t ^ fa[p]) { if (fa[e-> t]) { uo = p; vo = e-> t; dx = e-> v; break; } else { d[e-> t] = d[p] + 1; fa[e-> t] = p; df[e-> t] = e-> v; q[tl ++] = e-> t; } } } tlp = 0; for (int u = uo, v = vo; u ^ v; ++ tlp) if (d[u] > d[v]) a = u = fa[u]; else a = v = fa[v]; ++ tlp; for (int u = uo, v = vo; u ^ v; ) if (d[u] > d[v]) { int i(d[uo] - d[u]); lp[i] = u; le[i] = df[u]; u = fa[u]; } else { int i(tlp - d[vo] + d[v] - 1); lp[i] = v; le[i - 1] = df[v]; v = fa[v]; } lp[d[uo] - d[a]] = a; le[tlp - 1] = dx; for (int i = 0; i < tlp; ++ i) ol[lp[i]] = 1; } void dpTree(int p0) { static int q[maxn]; int hd(0), tl(1); q[0] = p0; while (hd < tl) { int p(q[hd ++]); for (edge* e = head[p]; e; e = e-> next) if (!ol[e-> t]) { ol[e-> t] = ol[p] + 1; q[tl ++] = e-> t; } } for (int i = tl - 1; i >= 0; -- i) { int p(q[i]); dint s2(0); md[p] = 0; for (edge* e = head[p]; e; e = e-> next) if (ol[e-> t] == ol[p] + 1) { dint v(md[e-> t] + e-> v); if (v > md[p]) { s2 = md[p]; md[p] = v; } else if (v > s2) s2 = v; } if (md[p] + s2 > ans) ans = md[p] + s2; } } struct dat { dint x, y, s; dat() {} dat(dint x0, dint y0) { x = x0, y = y0, s = 0; } dat(dat a, dat b) { s = max(max(a. s, b. s), a. x + b. y); x = max(a. x, b. x); y = max(a. y, b. y); } }; struct seg { int l, r; dat d; seg *ls, *rs; }; seg slst[maxn * 5], *sp(slst), *rt; #define midp(p) ((p->l+p->r)>>1) inline seg* sgtBuild(int l, int r) { seg *p(sp ++); p-> l = l; p-> r = r; if (l + 1 == r) { p-> d = dat(lv[l] + le[l], lv[l] - le[l]); } else { p-> ls = sgtBuild(l, midp(p)); p-> rs = sgtBuild(midp(p), r); p-> d = dat(p-> ls-> d, p-> rs-> d); } return p; } inline dat sgtQry(seg* p, int l, int r) { if (p-> l == l && p-> r == r) return p-> d; else if (r <= midp(p)) return sgtQry(p-> ls, l, r); else if (l >= midp(p)) return sgtQry(p-> rs, l, r); else return dat(sgtQry(p-> ls, l, midp(p)), sgtQry(p-> rs, midp(p), r)); } void dpLoop() { dint totl(0); for (int i = 0; i < tlp; ++ i) { lv[i + tlp] = lv[i]; le[i + tlp] = le[i]; lp[i + tlp] = lp[i]; totl += le[i]; } le[tlp * 2] = 0; for (int i = tlp * 2 - 1; i >= 0; -- i) le[i] += le[i + 1]; rt = sgtBuild(0, tlp * 2); dint cans(0x7fffffffffffffffll); for (int i = 0; i < tlp; ++ i) { cans = min(cans, sgtQry(rt, i, i + tlp). s); } ans = max(ans, cans); } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif scanf("%d", &n); memset(head, 0, sizeof(head)); for (int i = 0; i < n; ++ i) { int u, v, w; scanf("%d%d%d", &u, &v, &w); addEdge(u, v, w); addEdge(v, u, w); } findLoop(); ans = 0; for (int i = 0; i < tlp; ++ i) { dpTree(lp[i]); lv[i] = md[lp[i]]; } dpLoop(); printf("%.1lf\n", (double)ans / 2.0); }