HDU 4679 Terrorist’s destroy 解题报告

39 篇文章 0 订阅

2013 暑假多校训练 8 总结

题目

题意:

有一棵树,要删掉一条边,删边后形成两棵树,要求两棵树的最长直径的最大值乘以删掉的边权的值最小。

题解:

两次DFS:

第一次计算出从当前点到叶子的最长三条无公共边的链。

第二次,如果要删掉某条边,就可以知道两棵树的最长直径了:一条是当前子树的最长链,一条是祖先的不包含当前子树的最长链。


又忘了开栈开关……

据说这题的数据特别水,把边权全当1,输出最长链的短链也能过。


//Time:921ms
//Memory:14312KB
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define MAXN 100010
#define INF 1000000007
#define FI first
#define SE second
#define MP(x,y) make_pair(x,y)
pair<int,int> tree[MAXN][3];
int he[MAXN],to[MAXN*2],nex[MAXN*2],co[MAXN*2],id[MAXN*2],top;
int ans;
long long best;
void add(int u,int v,int w,int i)
{
    to[top]=v;
    nex[top]=he[u];
    co[top]=w;
    id[top]=i;
    he[u]=top++;
}
void upd(int h,int len,int whi)
{
    if(len>tree[h][0].FI)
        tree[h][2]=tree[h][1],tree[h][1]=tree[h][0],tree[h][0]=MP(len,whi);
    else    if(len>tree[h][1].FI)
        tree[h][2]=tree[h][1],tree[h][1]=MP(len,whi);
    else    if(len>tree[h][2].FI)
        tree[h][2]=MP(len,whi);
}
int dfs1(int h,int fa)
{
    for(int i=he[h];i!=-1;i=nex[i])
        if(fa!=to[i])
            upd(h,dfs1(to[i],h),to[i]);
    return tree[h][0].FI+1;
}
pair<int,int> mget(int h,int whi)
{
    pair<int,int> ret;
    if(whi==tree[h][0].SE)
        ret=MP(tree[h][1].FI+tree[h][2].FI,tree[h][1].FI);
    else    if(whi==tree[h][1].SE)
        ret=MP(tree[h][0].FI+tree[h][2].FI,tree[h][0].FI);
    else    ret=MP(tree[h][1].FI+tree[h][0].FI,tree[h][0].FI);
    return ret;
}
void dfs2(int h,int fa,int pre1,int pre2,int whi)
{
    long long tmp=max(max(pre2,pre1),mget(h,0).FI)*(long long)co[whi];
    if(h!=1&&(tmp<best||(tmp==best&&ans>id[whi])))
    {
        best=tmp;
        ans=id[whi];
    }
    pair<int,int> tpa;
    for(int i=he[h];i!=-1;i=nex[i])
        if(to[i]!=fa)
        {
            tpa=mget(h,to[i]);
            dfs2(to[i],h,max(pre1+1,tpa.SE),max(max(pre2,pre1+1+tpa.SE),tpa.FI),i);
        }
}
int main()
{
    //freopen("/home/moor/Code/input","r",stdin);
    int ncase,n;
    scanf("%d",&ncase);
    for(int h=1;h<=ncase;++h)
    {
        scanf("%d",&n);
        memset(he,-1,sizeof(he));
        memset(tree,0,sizeof(tree));
        top=0;
        for(int i=1;i<n;++i)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w,i);
            add(v,u,w,i);
        }
        ans=INF;
        best=100000000000000LL;
        dfs1(1,-1);
        dfs2(1,-1,-1,0,-1);
        printf("Case #%d: %d\n",h,ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值