【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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章