zoukankan      html  css  js  c++  java
  • CF835F Roads in the Kingdom

    题目描述:

    cf

    luogu

    题解:

    基环树拆环$dp$。

    先找环拆环,令$dp[i]$表示环上点$i$不经过环的最长链,$sum[i]$表示环上按某一确定顺序遍历顶点到第$i$个点的距离。

    这两个是基环树拆环后都要处理的。

    在树形$dp$先处理不经过环的最长链。

    然后处理经过环的。

    我们可以处理:

    1. $max_{l<r leq i}{  l子树内最长链端点到r子树内最长链端点距离}$
    2. $max_{i leq l<r}{  l子树内最长链端点到r子树内最长链端点距离}$
    3. $max_{r leq i}{  r子树内最长链端点到第一个点子树内最长链端点距离}$
    4. $max_{i leq l}{  l子树内最长链端点到最后一个点子树内最长链端点距离}$

    对于断每一条边我们都能$O(1)$出直径。

    最后两个$ans$取最大输出即可。

    时间复杂度$O(n)$。

    $set$也有$O(nlogn)$做法但是不如这个官方解法优秀。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N = 200050;
    template<typename T>
    inline void read(T&x)
    {
        T f = 1,c = 0;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
        x = f*c;
    }
    int n,hed[N],cnt=1;
    struct EG
    {
        int to,nxt;
        ll w;
    }e[2*N];
    void ae(int f,int t,ll w)
    {
        e[++cnt].to = t;
        e[cnt].nxt = hed[f];
        e[cnt].w = w;
        hed[f] = cnt;
    }
    int sta[2*N],tl,rt;
    ll ste[2*N];
    bool cir[N];
    bool vis[N];
    int dfs0(int u,int pre)
    {
        if(vis[u])
        {
            rt = u;
            return 1;
        }
        vis[u] = 1;
        for(int now,j=hed[u];j;j=e[j].nxt)
        {
            int to = e[j].to;
            if(j==pre)continue;
            if((now=dfs0(to,j^1)))
            {
                if(now==1)
                {
                    sta[++tl] = u;
                    ste[tl] = e[j].w;
                    cir[u] = 1;
                    if(u!=rt)return 1;
                }
                return 2;
            }
        }
        return 0;
    }
    ll dp[N],sum[2*N],ans=0x3f3f3f3f3f3f3f3fll,ans0;
    ll f[2][N],g[2][N];
    ll dfs1(int u,int pre)
    {
        for(int j=hed[u];j;j=e[j].nxt)
        {
            int to = e[j].to;
            if(j==pre||cir[to])continue;
            ll tmp = dfs1(to,j^1)+e[j].w;
            ans0 = max(ans0,dp[u]+tmp);
            dp[u] = max(dp[u],tmp);
        }
        return dp[u];
    }
    int main()
    {
    //    freopen("tt.in","r",stdin);
        read(n);
        for(int u,v,w,i=1;i<=n;i++)
        {
            read(u),read(v),read(w);
            ae(u,v,w),ae(v,u,w);
        }
        dfs0(1,0);
        for(int i=1;i<=tl;i++)dfs1(sta[i],0);
        for(int i=1;i<=tl;i++)sum[i]=sum[i-1]+ste[i];
        ll mx = -ste[1];
        for(int i=1;i<=tl;i++)
        {
            f[0][i] = max(f[0][i-1],dp[sta[i]]+sum[i]+mx);
            mx = max(mx,dp[sta[i]]-sum[i]);
            f[1][i] = max(f[1][i-1],dp[sta[i]]+sum[i]-sum[1]);
        }
        mx = sum[tl];
        for(int i=tl;i>=1;i--)
        {
            g[0][i] = max(g[0][i+1],dp[sta[i]]-sum[i]+mx);
            mx = max(mx,dp[sta[i]]+sum[i]);
            g[1][i] = max(g[1][i+1],dp[sta[i]]-sum[i]+sum[tl]);
        }
        ans = f[0][tl];
        for(int i=1;i<=tl;i++)
            ans = min(ans,max(max(f[0][i],g[0][i+1]),f[1][i]+g[1][i+1]+ste[1]));
        printf("%lld
    ",max(ans,ans0));
        return 0;
    }
    View Code
  • 相关阅读:
    常见makefile写法
    CMake入门指南
    CMAKE的使用
    Google NewSQL之Spanner
    Google Spanner (中文版)
    全球级的分布式数据库 Google Spanner原理
    idea刷新项目、清除项目缓存
    彻底理解Java的Future模式
    Elasticsearch 三种分页方式
    ElasticSearch 深度分页解决方案
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10785716.html
Copyright © 2011-2022 走看看