洛谷P4408 [NOI2003]逃学的小孩

链接

https://www.luogu.org/problem/show?pid=4408


大意


m a x { d i s [ A ] [ B ] + m i n ( d i s [ B ] [ C ] , d i s [ A ] [ C ] ) } max\{dis[A][B]+min(dis[B][C],dis[A][C])\} max{dis[A][B]+min(dis[B][C],dis[A][C])}


思路

m a x { d i s [ A ] [ B ] } max\{dis[A][B]\} max{dis[A][B]}这个用树的直径
m i n ( d i s [ B ] [ C ] , d i s [ A ] [ C ] ) min(dis[B][C],dis[A][C]) min(dis[B][C],dis[A][C])这个暴力


代码

#include
#include
#include
#define ri register int
using namespace std;int n,m,l[200001],p,q,tot,pr[200001];
struct node{int next,to,w;}e[400001];
inline void add(ri u,ri v,ri w){e[++tot]=(node){l[u],v,w};l[u]=tot;return;}
long long Ans,ans,dis[200001],f[200001];
inline char Getchar()
{
    static char buf[100000],*p1=buf+100000,*pend=buf+100000;
    if(p1==pend)
	{
        p1=buf; pend=buf+fread(buf,1,100000,stdin);
        if (pend==p1) return -1;
    }
    return *p1++;
}
inline long long read()
{
	char c;int d=1;long long f=0;
	while(c=Getchar(),!isdigit(c))if(c==45)d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=Getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
inline void write(register long long x)
{
	if(x<0)write(45),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+48);
	return;
}
inline void dp(ri x,ri fa)//求树的直径
{
	for(ri i=l[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if(y==fa) continue;
		dp(y,x);
		if(f[x]+f[y]+e[i].w>ans)
		{
			ans=f[x]+f[y]+e[i].w;
			p=pr[x];q=pr[y];//保存
		}
		if(f[y]+e[i].w>f[x])
		{
			f[x]=f[y]+e[i].w;
			pr[x]=pr[y];//连接
		}
	}
}
inline void dfs(ri x,ri fa,long long s)//暴力求距离
{
	dis[x]=min(s,dis[x]);
	for(ri i=l[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if(y==fa) continue;
		dfs(y,x,s+e[i].w);
	}
}
signed main()
{
	n=read();m=read();
	for(ri i=1;i<=n;i++) pr[i]=i,dis[i]=1e18;
	for(ri i=1,x,y,w;i<=m;i++) x=read(),y=read(),w=read(),add(x,y,w),add(y,x,w);
	dp(1,0);dfs(p,0,0);dfs(q,0,0);
	for(ri i=1;i<=n;i++) Ans=max(Ans,dis[i]);
	write(Ans+ans);
}

你可能感兴趣的:(树的直径,dp)