https://www.lydsy.com/JudgeOnline/problem.php?id=3124
第一问求树的直径 第二问求有多少边被所有直径覆盖
求第一问时把直径上的点存下来 枚举直径上的点 求一下不走直径上的点所能到达的最远距离 记为dis3 如果和直径的左端点距离相等 就把当前点到左端点的边都标记 这些边就是不符合条件的 和直径的右端点距离相等同样处理
要求的边时被所有直径覆盖的 如果有某个点的dis3等于到左右端点的距离 说明存在另外一条直径 该点到端点上的这些边没有被另外一条直径覆盖
复杂度还是o(n)的 因为不能走直径就相当于把这颗树分成了很多不连通的小部分 非直径上的点只会被走一次
#include <bits/stdc++.h>
using namespace std;
#define ll long long
struct node
{
int v;
ll w;
int next;
};
node edge[400010];
ll dis1[200010],dis2[200010],dis3[200010];
int first[200010],fa1[200010],fa2[200010],book[200010],pre[200010];
int n,num;
void addedge(int u,int v,ll w)
{
edge[num].v=v;
edge[num].w=w;
edge[num].next=first[u];
first[u]=num++;
}
void dfsI(int cur,int &p)
{
ll w;
int i,v;
for(i=first[cur];i!=-1;i=edge[i].next)
{
v=edge[i].v,w=edge[i].w;
if(v!=fa1[cur])
{
dis1[v]=dis1[cur]+w,fa1[v]=cur;
dfsI(v,p);
if(dis1[p]<dis1[v]) p=v;
}
}
}
void dfsII(int cur)
{
ll w;
int i,v;
for(i=first[cur];i!=-1;i=edge[i].next)
{
v=edge[i].v,w=edge[i].w;
if(v!=fa2[cur])
{
dis2[v]=dis2[cur]+w,fa2[v]=cur;
dfsII(v);
}
}
}
void dfsIII(int cur,ll &maxx)
{
ll w;
int i,v;
for(i=first[cur];i!=-1;i=edge[i].next)
{
v=edge[i].v,w=edge[i].w;
if(book[v]==0)
{
dis3[v]=dis3[cur]+w,book[v]=1;
maxx=max(maxx,dis3[v]);
dfsIII(v,maxx);
}
}
}
int main()
{
ll w,maxx,ans1;
int i,j,u,v,p1,p2,p,ans2;
scanf("%d",&n);
memset(first,-1,sizeof(first));
num=0;
for(i=1;i<=n-1;i++)
{
scanf("%d%d%lld",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
}
dis1[1]=0,fa1[1]=0;
p1=0;
dfsI(1,p1);
dis1[p1]=0,fa1[p1]=0;
p2=0;
dfsI(p1,p2);
ans1=dis1[p2];
//printf("***%d %d***\n",p1,p2);
dis2[p2]=0,fa2[p2]=0;
dfsII(p2);
p=p1,num=0;
while(p!=0)
{
pre[++num]=p;
book[p]=1;
p=fa2[p];
}
p=p1;
while(p!=0)
{
dis3[p]=0;
maxx=0;
dfsIII(p,maxx);
dis3[p]=maxx;
p=fa2[p];
}
/*
printf("***%d***\n",num);
for(i=1;i<=num;printfi++)
{
printf("*%d %lld %lld %lld*\n",pre[i],dis1[pre[i]],dis2[pre[i]],dis3[pre[i]]);
}
*/
memset(book,0,sizeof(book));
for(i=1;i<=num;i++)
{
if(dis3[pre[i]]==dis1[pre[i]]) for(j=i-1;j>=1&&book[j]==0;j--) book[j]=1;
}
for(i=num;i>=1;i--)
{
if(dis3[pre[i]]==dis2[pre[i]]) for(j=i;j<=num-1&&book[j]==0;j++) book[j]=1;
}
ans2=0;
for(i=1;i<=num-1;i++) ans2+=(book[i]==0);
printf("%lld\n%d\n",ans1,ans2);
return 0;
}