[NOI2013]快餐店 / CF835F Roads in the Kingdom (基环树)

题意

一颗基环树,选一对点使得这两个点的最短距离最大。

题解

相当于找基环树的直径,但是这个直径不是最长链,是基环树上的最短距离。

然后不会做。

然后看了ljh_2000的博客。

然后会了。

这道题最难的就是为什么枚举断边(ii+1)(i\to i+1)后,求出最长链是取min\min。实际上是因为这个最长链是求的经过了环的最长链,但是经过了环的最长链不一定是题目中要求的最短距离,所以枚举断边取min\min就是为了取小的那一段,而且一定不会错过答案。

.

CODE

听说CF835F的数据强点。不过要改一下输出和数据范围。

#pragma GCC optimize (3)
#include <bits/stdc++.h>
using namespace std;
char cb[1<<15],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
void read(int &res){
    char ch; for(;!isdigit(ch=getchar()););
    for(res=ch-'0';isdigit(ch=getchar());res=res*10+ch-'0');
}
typedef long long LL;
const int MAXN = 100005;
int n, seq[MAXN], stk[MAXN], indx, m;
bool inq[MAXN], vis[MAXN], flg[MAXN];
int fir[MAXN], to[MAXN<<1], nxt[MAXN<<1], wt[MAXN<<1], cnt = 1;
inline void link(int u, int v, int w) {
    to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt; wt[cnt] = w;
    to[++cnt] = u; nxt[cnt] = fir[v]; fir[v] = cnt; wt[cnt] = w;
}
void dfs(int u, int ff) {
    vis[u] = inq[u] = 1; stk[++indx] = u;
    for(int i = fir[u], v; i; i = nxt[i])
        if((i^1) != ff) {
            if(!vis[v = to[i]]) dfs(v, i);
            else {
                if(inq[v]) {
                    for(int i = indx; i; --i) {
                        flg[seq[++m] = stk[i]] = 1;
                        if(stk[i] == v) break;
                    }
                }
            }
        }
    inq[u] = 0; --indx;
}
LL dp[MAXN], chain;
LL DP(int u, int ff) {
    for(int i = fir[u], v; i; i = nxt[i])
        if((v=to[i]) != ff && !flg[v]) {
            chain = max(chain, dp[u] + DP(v, u) + wt[i]);
            dp[u] = max(dp[u], dp[v] + wt[i]);
        }
    return dp[u];
}
LL val[MAXN], len[MAXN];
LL pre[MAXN], f[MAXN];
LL suf[MAXN], g[MAXN];
int main () {
    //freopen("shuju.in", "r", stdin);
    read(n);
    for(int i = 1, u, v, w; i <= n; ++i) read(u), read(v), read(w), link(u, v, w);
    dfs(1, 0);
    for(int i = 1; i <= m; ++i) {
        val[i] = DP(seq[i], 0);
        for(int j = fir[seq[i]]; j; j = nxt[j])
            if(to[j] == seq[i%m+1]) len[i] = wt[j];
    }
    LL sum = 0, mx = 0;
    for(int i = 1; i <= m; ++i) {
        pre[i] = max(pre[i-1], sum + val[i]);
        f[i] = max(f[i-1], sum + mx + val[i]);
        mx = max(mx, val[i]-sum);
        sum += len[i];
    }
    sum = 0; mx = 0;
    for(int i = m; i >= 1; --i) {
        suf[i] = max(suf[i+1], sum + val[i]);
        g[i] = max(g[i+1], sum + mx + val[i]);
        mx = max(mx, val[i]-sum);
        sum += len[i-1];
    }
    LL ans = f[m];
    for(int i = 1; i < m; ++i)
        ans = min(ans, max(pre[i] + suf[i+1] + len[m], max(f[i], g[i+1])));
    ans = max(ans, chain);
    if(ans & 1) printf("%lld.5\n", ans/2);
    else printf("%lld.0\n", ans/2);
}
posted @ 2019-12-14 14:50  _Ark  阅读(99)  评论(0编辑  收藏  举报