传送门: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;
}