[BZOJ 1509] 逃学的小孩

Link:

BZOJ 1509 传送门

Solution:

一开始受样例影响又犯了想当然的毛病……图中的C点不一定在直径上!

3次$dfs$求出树的直径及直径的两个端点$rt1,rt2$到每个点的距离$d1,d2$,

则结果为$max\{ Diameter+min\{ d1[i],d2[i] \} \}$

Tips:如果要求出直径上每个点或求点到直径端点的距离时,最好还是用2次$dfs$的方法,而不使用一遍$dfs$法

Code:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN=2e5+10;
struct edge{int to,nxt,w;}e[MAXN<<2];
int n,m,rt1,rt2,head[MAXN],tot=-1;
ll d1[MAXN],d2[MAXN],dia=0,res=0;

void add_edge(int x,int y,int z)
{
    e[++tot].nxt=head[x];e[tot].to=y;e[tot].w=z;head[x]=tot;
    e[++tot].nxt=head[y];e[tot].to=x;e[tot].w=z;head[y]=tot;
}

void dfs(int x,int anc)
{
    for(int i=head[x];i!=-1;i=e[i].nxt)
    {
        if(e[i].to==anc) continue;
        d1[e[i].to]=max(d1[e[i].to],d1[x]+e[i].w);
        dfs(e[i].to,x);
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    memset(head,-1,sizeof(head));d1[0]=-1e15;
    for(int i=1;i<=m;i++)
    {
        int x,y,z;scanf("%d%d%d",&x,&y,&z);
        add_edge(x,y,z);
    }
    
    dfs(1,0);for(int i=1;i<=n;i++) if(d1[i]>d1[rt1]) rt1=i;
    memset(d1,0,sizeof(d1));d1[0]=-1e15;dfs(rt1,0);
    for(int i=1;i<=n;i++)
    {
        if(d1[i]>d1[rt2]) rt2=i;
        d2[i]=d1[i];dia=max(dia,d1[i]);
    }
    memset(d1,0,sizeof(d1));dfs(rt2,0);
    
    for(int i=1;i<=n;i++)
        res=max(res,dia+min(d1[i],d2[i]));
    printf("%lld",res);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/newera/p/9232303.html