题解:[NOI2003]逃学的小孩

Sol

题目大意

求树的直径,然后再求其余点到直径两端(中最小值)的最大值

题解

首先,一个很显然的结论
从A走到B(或从B走到A)要使得最长的话,就是树的直径,两遍bfs就ok了
然后从C走到A(或B),要使得最长的话,就暴力判一下呗

假设从A走到B最大值为a,从C走到A最大值为b
题目要求你使a+b最大
现在你让a最大,又让b最大
那a+b不久最大了

所以“水题”,就直接上代码了

#include
#include
#include
#include
using namespace std;
#define ll long long
#define rg register
#define inf 1e18
const int _=200100;
inline int read()
{
    char ch='!';int z=1,num=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')z=-1,ch=getchar();
    while(ch<='9'&&ch>='0')num=(num<<3)+(num<<1)+ch-'0',ch=getchar();
    return z*num;
}
int N,M;
struct hand{int to,next,w;}e[_<<1];
int cnt,head[_];
inline void link(int u,int v,int w)
{
    e[++cnt]=(hand){v,head[u],w};head[u]=cnt;
    e[++cnt]=(hand){u,head[v],w};head[v]=cnt;
}
ll disa[_],disb[_],d[_];
bool vis[_];
queue<int>Q;
inline int spfa(int S,ll d[])
{
    for(rg int i=1;i<=N;++i)d[i]=inf;
    d[S]=0;Q.push(S);vis[S]=1;
    while(!Q.empty())
    {
        rg int u=Q.front();Q.pop();
        for(rg int i=head[u];i;i=e[i].next)
        {
            rg int v=e[i].to;
            if(d[v]>d[u]+e[i].w)
            {
                d[v]=d[u]+e[i].w;
                if(!vis[v])
                {Q.push(v);vis[v]=1;}
            }
        }
        vis[u]=0;
    }
    rg ll Max=0;rg int t=0;
    for(rg int i=1;i<=N;++i)
        if(d[i]>Max)
            Max=d[i],t=i;
    return t;
}
int main()
{
    N=read();M=read();
    for(rg int i=1;i<=M;++i)
    {
        int x=read(),y=read(),z=read();
        link(x,y,z);
    }
    rg int a,b;
    a=spfa(1,d);
    b=spfa(a,disa);
    spfa(b,disb);
    rg ll ans=disa[b],Max=0;
    for(rg int i=1;i<=N;++i)
        Max=max(Max,min(disa[i],disb[i]));
    printf("%lld\n",ans+Max);
    return 0;
}

你可能感兴趣的:(题解组)