题意:
给出一个有n个结点,边有长度的树;
求这个树的直径,以及有多少边在所有的直径上;
题解:
树的直径就不用说了吧。。随便搜一下就可以;
而对于一个边在所有的直径上,等价于删掉这条边得到的两颗树中不存在一条长度等于直径的链;
那么问题就是快速求出删边之后两颗树的直径了;
这里我们采用乱搞大法!
总之其实就是维护一下几个状态,转移随便搞搞式子就OK了;
fs[x][0],fs[x][1],fs[x][2]分别表示从x出发,到某一儿子的子树,的最长链长度,次长链长度,第三长链长度;
ff[x]表示结点x的到它的父树中的最长链长度;
fz[x][0],fz[x][1]分别表示结点x的最长的儿子的子树中最长链长度,和次长的儿子的子树中最长链长度;
fl[x]表示结点x的父树中的最长链长度;
式子啥的贴出来也只是鬼畜,想看就自己到代码里翻?
总之情况考虑要周全,拍一拍就能AC了;
时间复杂度O(n);
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 210000
using namespace std;
typedef long long ll;
int next[N<<1],to[N<<1],val[N<<1],head[N],ce;
int fa[N],fv[N];
ll fs[N][3],ff[N],fl[N],fz[N][2];
void add(int x,int y,int v)
{
to[++ce]=y;
val[ce]=v;
next[ce]=head[x];
head[x]=ce;
}
void dfs1(int x)
{
ll temp;
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa[x])
{
fa[to[i]]=x;
fv[to[i]]=val[i];
dfs1(to[i]);
temp=fs[to[i]][0]+val[i];
if(temp>fs[x][0])
fs[x][2]=fs[x][1],fs[x][1]=fs[x][0],fs[x][0]=temp;
else if(temp>fs[x][1])
fs[x][2]=fs[x][1],fs[x][1]=temp;
else if(temp>fs[x][2])
fs[x][2]=temp;
temp=max(fs[to[i]][0]+fs[to[i]][1],fz[to[i]][0]);
if(temp>fz[x][0])
fz[x][1]=fz[x][0],fz[x][0]=temp;
else if(fs[to[i]][0]+fs[to[i]][1]>fz[x][1])
fz[x][1]=temp;
}
}
}
void dfs2(int x)
{
if(fa[x])
ff[x]=max(ff[fa[x]],fs[fa[x]][0]==fs[x][0]+fv[x]?fs[fa[x]][1]:fs[fa[x]][0])+fv[x],
fl[x]=max(max(fz[fa[x]][0]==max(fz[x][0],fs[x][0]+fs[x][1])?fz[fa[x]][1]:fz[fa[x]][0],fl[fa[x]]),fs[x][0]+fv[x]==fs[fa[x]][0]?
max(ff[fa[x]]+fs[fa[x]][1],fs[fa[x]][1]+fs[fa[x]][2]):
(fs[x][0]+fv[x]==fs[fa[x]][1]?
max(ff[fa[x]]+fs[fa[x]][0],fs[fa[x]][0]+fs[fa[x]][2]):
max(ff[fa[x]]+fs[fa[x]][0],fs[fa[x]][0]+fs[fa[x]][1])
));
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa[x])
{
dfs2(to[i]);
}
}
}
int main()
{
int n,m,i,j,k,x,y,v,cnt;
ll ans;
scanf("%d",&n);
for(i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&v);
add(x,y,v),add(y,x,v);
}
dfs1(1);
dfs2(1);
for(i=1,ans=0;i<=n;i++)
ans=max(ans,max(ff[i],fs[i][1])+fs[i][0]);
printf("%lld\n",ans);
for(i=2,cnt=0;i<=n;i++)
{
if(
max(max(fs[i][0]+fs[i][1],fz[i][0]),
max(fl[i],fs[i][0]+fv[i]==fs[fa[i]][0]?
max(ff[fa[i]]+fs[fa[i]][1],fs[fa[i]][1]+fs[fa[i]][2]):
(fs[i][0]+fv[i]==fs[fa[i]][1]?
max(ff[fa[i]]+fs[fa[i]][0],fs[fa[i]][0]+fs[fa[i]][2]):
max(ff[fa[i]]+fs[fa[i]][0],fs[fa[i]][0]+fs[fa[i]][1])
)
))
<ans)
cnt++;
}
printf("%d\n",cnt);
return 0;
}