HDU 4679 Terrorist’s destroy (拆边+树的直径)

给一棵树,每条边上都有一个权值,去掉树上任意一条边之后,分成两个子树,两个子树的最长路与这条边上的权值相乘,的到一个乘积。问去掉那一条边可以使这个乘积最小。

首先找到树上的最长路,那么删边的时候有两种情况:

1. 这条边不是最长路上的边

2. 这条边是最长路上的边

对于第一种情况,很容易计算出乘积。

对于第二种情况,只需要计算出被分成的两个子树里面的最长路径长度即可,这个可以预处理一下。分析可以发现,这种情况下,两棵子树的最长路,一定是以整棵树的最长路的两个端点为起始点的,因此只需要预处理出所有点到两个端点的距离,然后根据删除的最长路边求两颗子树中的最大值即可。

所有预处理都是dfs……

My code:

#pragma comment(linker,"/STACK:102400000,102400000")
#include 
#include 
#include 
using namespace std;
#define N 100100
int n;
int head[N],cnt,len,ans,id;
int dis_s[N],dis_t[N],mx_s[N],mx_t[N];
struct Edge
{
    int next,to,w,id;
}e[N*2];
void add_edge(int a,int b,int w,int id)
{
    e[cnt].id=id;
    e[cnt].to=b;
    e[cnt].w=w;
    e[cnt].next=head[a];
    head[a]=cnt++;
}
void dfs(int u, int fa, int dis[])
{
    for(int i = head[u]; i != -1; i = e[i].next)
    {
        int v=e[i].to;
        if(v!=fa)
        {dis[v]=dis[u]+1;dfs(v,u,dis);}
    }
}
void get_max(int u, int fa, int mx[],int dis[])
{
    mx[u]=dis[u];
    for(int i = head[u]; i != -1; i = e[i].next)
    {
        int v=e[i].to;
        if(v!=fa)
        {
            get_max(v,u,mx,dis);
            mx[u]=max(mx[u],mx[v]);
        }
    }
}
void dfs2(int u, int fa)
{
    for(int i = head[u]; i != -1; i = e[i].next)
    {
        int v=e[i].to;
        if(v!=fa)
        {
            int w;
            if(dis_s[u]+dis_t[v]+1==len) w=e[i].w*max(mx_s[u],mx_t[v]);
            else w=e[i].w*len;
            if(w


你可能感兴趣的:(图论)