[BZOJ]3246: [Ioi2013]Dreaming 暴力乱搞

Description
Serpent(水蛇)生活的地方有N个水坑,编号为0,…,N - 1,有M条双向小路连接这些水坑。每两个水坑之间至多有一条路径(路径包含一条或多条小路)相互连接,有些水坑之间根本无法互通(即M ≤ N-1 )。Serpent走过每条小路需要一个固定的天数,不同的小路需要的天数可能不同。Serpent的朋友袋鼠希望新修 N - M - 1条小路,让Serpent可以在任何两个水坑间游走。袋鼠可以在任意两个水坑之间修路,Serpent通过每条新路的时间都是L天。袋鼠希望找到一种修路方式使得修路之后Serpent在每两个水坑之间游走的最长时间最短。
举例说明
上图中有12个水坑8条小路( N = 12, M = 8)。假如L = 2 ,即Serpent通过任何一条新路都需要2天。那么,袋鼠可以修建3条新路:
水坑1和水坑2之间;
水坑1和水坑6之间;
水坑4和水坑10之间。
上图显示了修路后的最终状态。从水坑0走到水坑11的时间最长,需要18天。这是 最佳结果,无论袋鼠如何选择修路方式,总会存在一些水坑对,Serpent需要18天 或者更长时间从其中一个走到另一个。

题解:

首先预处理出每个点的作为起点的最长路和次长路,然后根据这个就可以求出每棵树哪个点的最长路最短,那么若其它树与这棵树相连,就连这个点(这个显然),然后对每棵树的这个点的最长路从大到小排序,然后两两合并(这个自己画画就知道正确性显然了),维护新树的最长路最短路即可。

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=500010;
int n,m;
LL l;
struct Edge{int y,next;LL d;}e[Maxn<<1];
int last[Maxn],len=0;
void ins(int x,int y,LL d){int t=++len;e[t].y=y;e[t].d=d;e[t].next=last[x];last[x]=t;}
LL mx1[Maxn],mx2[Maxn],tmp;
bool vis[Maxn];
int p[Maxn],lp=0,ansp;
int rt;
void dfs1(int x,int fa)
{
    mx1[x]=0;vis[x]=true;
    for(int i=last[x];i;i=e[i].next)
    {
        int y=e[i].y;
        if(y==fa)continue;
        dfs1(y,x);
        if(e[i].d+mx1[y]>=mx1[x])
        {
            mx2[x]=mx1[x];
            mx1[x]=e[i].d+mx1[y];
        }
        else if(e[i].d+mx1[y]>mx2[x])mx2[x]=e[i].d+mx1[y];
    }
}
LL ans=0;
void dfs2(int x,int fa,LL d)
{
    LL tot=0;
    if(fa)
    {
        if(mx1[fa]==d+mx1[x])
        {
            if(mx2[fa]+d>=mx1[x])
            {
                mx2[x]=mx1[x];
                mx1[x]=mx2[fa]+d;
            }
            else if(mx2[fa]+d>mx2[x])mx2[x]=mx2[fa]+d;
        }
        else
        {
            if(mx1[fa]+d>=mx1[x])
            {
                mx2[x]=mx1[x];
                mx1[x]=mx1[fa]+d;
            }
            else if(mx1[fa]+d>mx2[x])mx2[x]=mx1[fa]+d;
        }
    }
    if(mx1[x]<tmp)tmp=mx1[x],ansp=x;
    ans=max(ans,mx1[x]+mx2[x]);
    for(int i=last[x];i;i=e[i].next)
    {
        int y=e[i].y;
        if(y==fa)continue;
        dfs2(y,x,e[i].d);
    }
}
bool cmp(int x,int y){return mx1[x]>mx1[y];}
int main()
{
    scanf("%d%d%lld",&n,&m,&l);
    for(int i=1;i<=n;i++)vis[i]=false,mx2[i]=0;
    for(int i=1;i<=m;i++)
    {
        int x,y;LL d;
        scanf("%d%d%lld",&x,&y,&d);x++;y++;
        ins(x,y,d);ins(y,x,d);
    }
    for(int i=1;i<=n;i++)
    if(!vis[i])
    {
        tmp=(1LL<<60);
        dfs1(i,0);dfs2(i,0,0);
        p[++lp]=ansp;
    }
    sort(p+1,p+1+lp,cmp);
    for(int i=2;i<=lp;i++)
    {
        int t1=p[i-1],t2=p[i];
        ans=max(max(mx1[t1]+mx2[t1],mx1[t2]+mx2[t2]),mx1[t1]+mx1[t2]+l);
        LL tmp1=mx1[t1];
        if(l+mx1[t2]>=mx1[t1])
        {
            mx2[t1]=mx1[t1];
            mx1[t1]=l+mx1[t2];
        }
        else if(l+mx1[t2]>mx2[t1])mx2[t1]=l+mx1[t2];
        if(l+tmp1>=mx1[t2])
        {
            mx2[t2]=mx1[t2];
            mx1[t2]=l+tmp1;
        }
        else if(l+tmp1>mx2[t2])mx2[t2]=l+tmp1;
        if(mx1[t1]<mx1[t2])p[i]=t1;
        else p[i]=t2;
    }
    printf("%lld",ans);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值