题意:
给出一个有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; }