zoukankan      html  css  js  c++  java
  • [NOI2013]快餐店 / CF835F Roads in the Kingdom (基环树)

    题意

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

    题解

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

    然后不会做。

    然后看了ljh_2000的博客。

    然后会了。

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

    .

    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
    ", ans/2);
        else printf("%lld.0
    ", ans/2);
    }
    
  • 相关阅读:
    HDU 3565 Bi-peak Number(数位DP)题解
    FJNU Fang G and his Friends(状压DP)题解
    newcoder 小A的柱状图(单调栈)题解
    CodeForces 518E Arthur and Questions(贪心 + 思维)题解
    装饰器来激活生成器
    迭代器(Iterator)和生成器(generator)浅析
    简单的获取网页样式元素(装饰器实现)
    多层装饰器的调用及执行顺序
    三角形的输出
    简单的用户登录(文件处理)
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039206.html
Copyright © 2011-2022 走看看