zoukankan      html  css  js  c++  java
  • 【bzoj3246】 Ioi2013—Dreaming

    www.lydsy.com/JudgeOnline/problem.php?id=3246 (题目链接)

    题意

      给出一棵不完全的树,要求在树上连最少的边使得所有点联通,并且使得两点间最大距离最小。

    Solution 

      今天考试题,有情况没考虑到。。。 

      http://www.ccf.org.cn/resources/1190201776262/fujian/xuhaoran2013-07-25-03_33_55.pdf 

      做法的话其实很简单。我们先把每个连通块两遍dfs,O(n)的找出块内的“接点”和直径,至于怎么找,自己YY一下吧,很简单的。然后考虑将所有连通块联通,不妨将每个连通块看成一个点,将连通块内到“接点”的最远距离看成点权,那么一定是连成一棵菊花树。 

      答案一共有3种情况。第一,是一个连通块内的直径。第二,是点权最大和次大的两个连通块之间的距离。第三是点权次大和次次大的连通块之间的距离。

    代码

    // bzoj3246
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define inf 2147483640
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    
    const int maxn=500010;
    struct edge {int to,next;LL w;}e[maxn<<1];
    LL vis[maxn],head[maxn],a[maxn],f[maxn][2],son[maxn];
    LL cnt,sum,n,m,L,tt,tmp,d,ans;
    
    void link(int u,int v,LL w) {
        e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;e[cnt].w=w;
        e[++cnt].to=u;e[cnt].next=head[v];head[v]=cnt;e[cnt].w=w;
    }
    bool cmp(LL a,LL b) {
        return a>b;
    }
    void dfs1(int x,int fa) {   //x的子树中到x的最远距离和次远距离
        vis[x]=1;
        for (int i=head[x];i;i=e[i].next) if (!vis[e[i].to]) {
                dfs1(e[i].to,x);
                if (f[e[i].to][0]+e[i].w>f[x][0]) {
                    son[x]=e[i].to;f[x][0]=f[e[i].to][0]+e[i].w;
                }
            }
        for (int i=head[x];i;i=e[i].next)
            if (e[i].to!=fa && e[i].to!=son[x]) f[x][1]=max(f[x][1],f[e[i].to][0]+e[i].w);
    }
    void dfs2(int x,LL d,int fa) {   //整棵树到x的最远距离
        if (d>f[x][0]) {
            f[x][1]=f[x][0];son[x]=fa;f[x][0]=d;
        }
        else if (d>f[x][1]) f[x][1]=d;
        tt=min(tt,f[x][0]);
        ans=max(ans,f[x][0]);
        for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa) {
                if (e[i].to!=son[x]) dfs2(e[i].to,f[x][0]+e[i].w,x);
                else dfs2(e[i].to,f[x][1]+e[i].w,x);
            }
    }
    int main() {
        scanf("%lld%lld%lld",&n,&m,&L);
        for (int u,v,i=1;i<=m;i++) {
            LL w;
            scanf("%d%d%lld",&u,&v,&w);
            link(u,v,w);
        }
        for (int i=0;i<n;i++) if (!vis[i]) {
                tt=inf;
                dfs1(i,n);
                dfs2(i,0,n);
                a[++sum]=tt;
            }
        sort(a+1,a+1+sum,cmp);
        if (sum>=2) ans=max(ans,a[1]+a[2]+L);
        if (sum>=3) ans=max(ans,a[2]+L+L+a[3]);
        printf("%lld",ans);
        return 0;
    }
    

      

    This passage is made by MashiroSky.
  • 相关阅读:
    一个很好的博客 -----------------十年风雨,一个普通程序员的成长之路(五)
    项目中遇到的问题-----时间间隔查询
    不懂CPU工作原理又如何 ---CSDN
    鸿蒙OS横空出世-----
    关于项目中遇到的问题-- excel工具选择
    关于项目中遇到的问题-- 百度disconf 分布式配置中心
    SpringBoot使用邮件发送
    SpringBoot使用OkHttp
    Java8 获取当天日期的前一天
    如何将数字转为百分比?
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/5914026.html
Copyright © 2011-2022 走看看