求有多少条边:满足所有直径都经过该边。
两边树形dp,一遍以点做dp求出直径的个数,再以边做dp判断在直径上边的个数。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=200005;
const int inf=0x3f3f3f3f;
typedef long long ll;
int n;
int head[N],tot,ans;
struct aa
{
int to,pre;ll dis;
}edge[N*2];
void addedge(int u,int v,ll d) {edge[++tot].to=v;edge[tot].pre=head[u];edge[tot].dis=d;head[u]=tot;}
ll dis[N];
ll MX,ANS,f[N];
void dfs(int u,int fa)
{
int v;ll tmp;
dis[u]=0;f[u]=1;
for (int i=head[u];i;i=edge[i].pre)
if ((v=edge[i].to)!=fa)
{
dfs(v,u);
tmp=edge[i].dis+dis[v];
if (tmp+dis[u]>MX)
{
MX=tmp+dis[u];
ANS=f[v]*f[u];
}
else if (tmp+dis[u]==MX) ANS+=f[v]*f[u];
if (tmp>dis[u]) dis[u]=tmp,f[u]=f[v];
else if (tmp==dis[u]) f[u]+=f[v];
}
}
void dfs(int u,int fa,ll mx,ll ff)
{
ll tmp,fi=mx,se=0,fic=ff,sec=1;
int v;
for (int i=head[u];i;i=edge[i].pre)
if ((v=edge[i].to)!=fa)
{
tmp=dis[v]+edge[i].dis;
if (tmp>fi) se=fi,sec=fic,fi=tmp,fic=f[v];
else if (tmp==fi) fic+=f[v];
else if (tmp>se) se=tmp,sec=f[v];
else if (tmp==se) sec+=f[v];
}
for (int i=head[u];i;i=edge[i].pre) if ((v=edge[i].to)!=fa)
if (dis[v]+edge[i].dis==fi)
{
if (fic>f[v])
{
if (dis[v]+edge[i].dis+fi==MX&&(fic-f[v])*f[v]==ANS) ans++;
dfs(v,u,fi+edge[i].dis,fic-f[v]);
}
else
{
if (dis[v]+edge[i].dis+se==MX&&sec*f[v]==ANS) ans++;
dfs(v,u,se+edge[i].dis,sec);
}
}
else
{
if (dis[v]+edge[i].dis+fi==MX&&fic*f[v]==ANS) ans++;
dfs(v,u,fi+edge[i].dis,fic);
}
}
int main()
{
scanf("%d",&n);
int u,v;ll d;
for (int i=1;i<n;i++)
{
scanf("%d%d%lld",&u,&v,&d);
addedge(u,v,d);addedge(v,u,d);
}
dfs(1,0);
dfs(1,0,0,1);
// printf("%d\n",ANS);
printf("%lld\n%d",MX,ans);
return 0;
}
本文介绍了一种使用树形动态规划的方法来解决特定类型的图论问题——寻找一棵树中满足所有直径都经过的边的数量。通过两次树形DP分别计算直径数量及满足条件的边数。

714

被折叠的 条评论
为什么被折叠?



