luogu P3304 [SDOI2013]直径
树的直径两遍dfs救星了
至于一定在直径中的边数,可以发现这些边一定是连续的(不然你两条直径中间能有空挡?),然后,如果某个点往下有多条直径,那么这条点以下都不算入答案.所以以直径分别两端点为根,找出这样离根最近的点(注意最远的点就是另一个端点),然后找到那两个点的距离就是答案
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define db double
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
const int N=200000+10;
il LL rd()
{
re LL x=0,w=1;re char ch=0;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int to[N<<1],nt[N<<1],hd[N],tot=1;
LL w[N<<1],di[N],f[N],lent;
bool v[N];
il void add(int x,int y,LL z)
{
++tot;to[tot]=y;nt[tot]=hd[x];w[tot]=z;hd[x]=tot;
++tot;to[tot]=x;nt[tot]=hd[y];w[tot]=z;hd[y]=tot;
}
int n,fa[N];
il int dfs(int x,int ffa)
{
int xx=0;
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(y==ffa) continue;
fa[y]=x,di[y]=di[x]+w[i];
int yy=dfs(y,x);
if(di[xx]<di[yy]) xx=yy;
}
return xx?xx:x;
}
il int dd(int x,int ffa)
{
f[x]=0;
int xx=0,cnt=0;
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(y==ffa) continue;
int yy=dd(y,x);
if(!xx) xx=yy;
f[x]=max(f[x],f[y]+w[i]);
if(di[x]+f[y]+w[i]==lent&&ffa) ++cnt;
}
return (cnt>1&&v[x])?x:xx;
}
int main()
{
int aa,bb,c,d,an=0;
n=rd();
for(int i=1;i<n;i++)
{
int x=rd(),y=rd(),z=rd();
add(x,y,z);
}
aa=1;
di[1]=fa[1]=0;aa=dfs(1,0);
di[aa]=fa[aa]=0;bb=dfs(aa,0);
lent=di[bb];
int now=bb;
while(now) v[now]=true,now=fa[now];
c=dd(aa,0);if(!c) c=bb;
di[bb]=fa[bb]=0,dfs(bb,0);
d=dd(bb,0);if(!d) d=aa;
while(d!=c) ++an,d=fa[d];
printf("%lld\n%d\n",lent,an);
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步