传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3242
这道题简直蛋疼。。。
首先,如果这是一棵树的话,那么答案就是直径的长度/2,这是没有疑问的,但现在多了一个环,
于是我们就得到了一个60分算法,枚举环上的每一条边,再求直径,取最小值/2即可,但对于n <= 100000 的数据规模我们怎么办呢。
我们注意到树的直径要么经过环上的一段,要么就是一棵子树的最长链,对于后面一种情况,我们有经典的树dp做法。而对于前一种情况,
对环求一个前缀和,则两个点i,j的答案可以表示为s[j] - s[i] + f[j] + f[i],于是我们可以将数组延伸一倍,用线段树维护删去一条边后的区间
的f[i] - s[i], f[i] + s[i]的最大值,通过简单的证明(1)得到,f[i] - s[i]的最大值不会出现在f[i] + s[i]的最大值之后,于是我们就只需分两类讨论,
一类为位置不等,这种直接更新答案即可。另一类为位置相等,那么我们就只需考虑是留下f[i] - s[i]的最大值还是留下f[i] + s[i]的最大值。,
最后,由于数组开小,所以调试了一下午。。。我这种蒟蒻该怎么办啊TAT。。。
(1) 设f[i] - s[i] 的最大值位置为i,f[i] + s[i]的最大值位置为j,若i > j, s[i] > s[j] 则 f[i] > f[j],
那么f[i] + s[i] > f[j] + s[j]与条件矛盾,所以不可能存在这种情况。
#include <iostream> #include <cstdio> #include <cstring> #include <list> #include <queue> using namespace std; typedef long long LL; #define INF 100000000000000000LL #define idx(l, r) ((l + r) | (l != r)) #define mid ((l + r) >> 1) const int maxn = 100010; queue <int> q; int fir[maxn], next[maxn * 2], edge[maxn * 2], val[maxn * 2]; int cir[maxn * 2], dig[maxn]; bool vis[maxn]; LL f[maxn], g[maxn], d[maxn], s[maxn * 2]; LL mx1[maxn * 4], mx2[maxn * 4], p1[maxn * 4], p2[maxn * 4]; LL ans, res, ans1, ans2; int n, cnt, len, pos1, pos2; void addedge(int a, int b, int c) { edge[cnt] = b; next[cnt] = fir[a]; fir[a] = cnt; val[cnt ++] = c; return; } void get(int &tmp) { tmp = 0; char ch = getchar(); for(; ch < '0' || ch > '9'; ch = getchar()); for(; ch >= '0' && ch <= '9'; ch = getchar()) tmp = tmp * 10 + ch - '0'; return; } void push_up1(int l, int r) { if(mx1[idx(l, mid)] > mx1[idx(mid + 1, r)]) { mx1[idx(l, r)] = mx1[idx(l, mid)]; p1[idx(l, r)] = p1[idx(l, mid)]; } else { mx1[idx(l, r)] = mx1[idx(mid + 1, r)]; p1[idx(l, r)] = p1[idx(mid + 1, r)]; } return; } void push_up2(int l, int r) { if(mx2[idx(l, mid)] >= mx2[idx(mid + 1, r)]) { mx2[idx(l, r)] = mx2[idx(l, mid)]; p2[idx(l, r)] = p2[idx(l, mid)]; } else { mx2[idx(l, r)] = mx2[idx(mid + 1, r)]; p2[idx(l, r)] = p2[idx(mid + 1, r)]; } return; } void insert1(int l, int r, int p, LL v) { if(l == r) { mx1[idx(l, r)] = v; p1[idx(l, r)] = p; return; } if(p <= mid) insert1(l, mid, p, v); else insert1(mid + 1, r, p, v); push_up1(l, r); return; } void insert2(int l, int r, int p, LL v) { if(l == r) { mx2[idx(l, r)] = v; p2[idx(l, r)] = p; return; } if(p <= mid) insert2(l, mid, p, v); else insert2(mid + 1, r, p, v); push_up2(l, r); return; } void ask1(int l, int r, int a, int b) { if(l > b || r < a) return; if(a <= l && r <= b) { if(mx1[idx(l, r)] > ans1 || (mx1[idx(l, r)] == ans1 && p1[idx(l, r)] > pos1)) { ans1 = mx1[idx(l, r)]; pos1 = p1[idx(l, r)]; } return; } ask1(l, mid, a, b); ask1(mid + 1, r, a, b); return; } void ask2(int l, int r, int a, int b) { if(l > b || r < a) return; if(a <= l && r <= b) { if(mx2[idx(l, r)] > ans2 || (mx2[idx(l, r)] == ans2 && p2[idx(l, r)] < pos2)) { ans2 = mx2[idx(l, r)]; pos2 = p2[idx(l, r)]; } return; } ask2(l, mid, a, b); ask2(mid + 1, r, a, b); return; } void solve(int x) { int nxt, rt = x; cir[++len] = x; s[len] = 0; for(int i = fir[x]; ~i ; i = next[i]) { int v = edge[i]; if(!vis[v]) { nxt = v; cir[++len] = nxt; s[len] = val[i]; break; } } while(nxt) { vis[x] = true; int tmp = 0; for(int i = fir[nxt]; ~i ; i = next[i]) { int v = edge[i]; if(!vis[v]) { tmp = v; cir[++len] = tmp; s[len] = s[len - 1] + (LL)val[i]; break; } } x = nxt; nxt = tmp; } for(int i = fir[x]; ~i ; i = next[i]) { int v = edge[i]; if(v == rt) { cir[++len] = rt; s[len] = s[len - 1] + (LL)val[i]; break; } } len --; for(int i = 2; i <= len; i ++) { cir[len + i] = cir[i]; s[len + i] = s[len + i - 1] + s[i] - s[i - 1]; } for(int i = 1; i <= len * 2; i ++) { insert1(1, len * 2, i, f[cir[i]] + s[i]); insert2(1, len * 2, i, f[cir[i]] - s[i]); } for(int i = len + 1; i <= len * 2; i ++) { int st = i - len + 1; ans1 = ans2 = -INF; pos1 = pos2 = 0; ask1(1, len * 2, st, i); ask2(1, len * 2, st, i); if(pos1 != pos2) { ans = min(ans, max(ans1 + ans2, res)); } else { LL tmp1, tmp2, pp = -INF; if(pos1 < i) { tmp1 = ans1; tmp2 = pos1; ans1 = -INF; pos1 = 0; ask1(1, len * 2, tmp2 + 1, i); pp = max(pp, ans1 + ans2); ans1 = tmp1; pos1 = tmp2; } if(pos2 > st) { tmp1 = ans2; tmp2 = pos2; ans2 = -INF; pos2 = 0; ask2(1, len * 2, st, tmp2 - 1); pp = max(pp, ans1 + ans2); ans2 = tmp1; pos2 = tmp2; } ans = min(ans, max(pp, res)); } } return; } int main() { memset(fir, -1, sizeof(fir)); for(int i = 0; i < maxn * 4; i ++) { mx1[i] = mx2[i] = -INF; } get(n); int u, v, w; for(int i = 1; i <= n; i ++) { get(u); get(v); get(w); addedge(u, v, w); addedge(v, u, w); dig[u] ++; dig[v] ++; } for(int i = 1; i <= n; i ++) { if(dig[i] == 1) q.push(i); } while(!q.empty()) { int t = q.front(); q.pop(); d[t] = max(d[t], f[t] + g[t]); for(int i = fir[t]; ~i ; i = next[i]) { int v = edge[i]; if(vis[v]) continue; if(f[t] + val[i] > f[v]) { g[v] = f[v]; f[v] = f[t] + val[i]; } else if(f[t] + val[i] > g[v]) { g[v] = f[t] + val[i]; } d[v] = max(d[v], d[t]); dig[v] --; if(dig[v] == 1) q.push(v); } vis[t] = true; } for(int i = 1; i <= n; i ++) { if(!vis[i]) d[i] = max(d[i], f[i] + g[i]); res = max(res, d[i]); } ans = INF; for(int i = 1; i <= n; i ++) { if(!vis[i]) { solve(i); break; } } printf("%.1lf\n", (double)ans / 2.0); return 0; }