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;
}