删边

Description
  给出N个点,N-1条边的连通图.
  现要求删除一条边,使得连通块的直径总和最大.所谓连通块的直径是指连通块中最远两点之间的距离。
     问:直径总和最大是多少?

Input
  文件名为 delete.in
  第一行正整数N.
  接下来N-1行.每行两个数,A,B,LEN表示A,B(1<=A,B<=N)有一条长度为Len(1<=Len<=1000)的边连接着.

Output
  文件名为 delete.out
  一个数Ans.直径总和的最大值.

Sample Input
10
2 1 982
3 1 169
4 1 934
5 1 325
6 1 735
7 1 675
8 2 302
9 3 450
10 5 173

Sample Output
2668

Data Constraint

Hint
【数据范围】
  30% N<=100
  70% N<=5000
  100% N<=100000
.
.
.
.
.
.

分析

我们要预处理出每一棵子树的直径和子树中的最远点,次远点和子树中过x的最长链、次长链和次次长链
那么考虑删去一条边后直径有哪几种情况
①在x的子树里
②在x上面的联通块的直径
③x子树没被删去的最远点与x上方最远点的和
④在x不同子树上最远的点的和

考虑一下怎么求:
①预处理得出
②在递归时可以记录当前经过联通块的最大值
③x子树里的在预处理里已经求出来,那么不在x子树里的也就是递归经过x的最长链
④也就是在x子树里不含被删子树的最远点和次远点
.
.
.
.
.

程序:
#include<iostream>
using namespace std;
int m[2][100001][4],d[2][100001][4],fa[100001],head[100001],dis[100001],ans,n,cnt;

struct edge 
{ 
    int to,from,v; 
}rp[200001];

void insert(int x,int y,int z) 
{ 
    rp[++cnt].to=y;rp[cnt].v=z;rp[cnt].from=head[x];head[x]=cnt; 
}

void dfs(int x)
{
    for (int i=head[x];i;i=rp[i].from)
    {
        int w=rp[i].to;
        if (w!=fa[x])
        {
            fa[w]=x;
            dfs(w);
            dis[x]=max(dis[x],dis[w]);
            if (dis[w]>m[0][x][1])
            {
                m[0][x][2]=m[0][x][1];
                m[0][x][1]=dis[w];
                d[0][x][1]=w;
            } else 
            if (dis[w]>m[0][x][2]) m[0][x][2]=dis[w];
            int v=m[1][w][1]+rp[i].v;
            if (v>m[1][x][1])
            {
                m[1][x][3]=m[1][x][2];
                m[1][x][2]=m[1][x][1];
                m[1][x][1]=v;
                d[1][x][2]=d[1][x][1];
                d[1][x][1]=w;
            } else
            if (v>m[1][x][2])
            {
                m[1][x][3]=m[1][x][2];
                m[1][x][2]=v;
                d[1][x][2]=w;
            } else 
            if (v>m[1][x][3]) m[1][x][3]=v;
        }
    }
    dis[x]=max(m[1][x][1]+m[1][x][2],m[0][x][1]);
}

void find(int x,int a,int b)        
{
    int m1,m2,m3;
    if (x!=1) ans=max(ans,dis[x]+a);
    for (int i=head[x];i;i=rp[i].from)
    {
        int v=rp[i].to;
        if (v!=fa[x])
        {
            if (d[1][x][1]==v)
            {
                m1=m[1][x][2];
                m2=m[1][x][2]+m[1][x][3];
            } else
            {
                m1=m[1][x][1];
                if (d[1][x][2]==v) m2=m[1][x][1]+m[1][x][3]; else m2=m[1][x][1]+m[1][x][2];
            }
            if (d[0][x][1]==v) m3=m[0][x][2]; else m3=m[0][x][1];
            find(v,max(max(a,m3),max(m1+b,m2)),max(b,m1)+rp[i].v);
        }
    }
}
int main()
{
    cin>>n;
    for (int i=1;i<=n-1;i++)
    {
        int x,y,z;
        cin>>x>>y>>z;
        insert(x,y,z); 
        insert(y,x,z);
    }
    dfs(1);
    find(1,0,0);
    cout<<ans;
    return 0;
}
原文地址:https://www.cnblogs.com/YYC-0304/p/9499936.html