P4408 [NOI2003] 逃学的小孩

思路:找出树上的直径端点,然后枚举树上的其他点,答案取最大值。(弱弱我一开始找直径中点,然后dfs求除直径外距离中点的最长链统计答案,不知道为什么错了捏)

/**********
明天你是否会想起
昨天未调完的题
明天你是否还惦记
考场写挂的暴力
**********/
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e18;//按题目要求随时修改.
void read(int &x){
    int f=1;x=0;char s=getchar();
    while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
    while(s<='9'&&s>='0'){x=x*10%mod+(s-'0')%mod;s=getchar();}//改成了取模~~
    x=x%mod*f;//改成了取模~
}
typedef pair<int,int>PII;
const int N=2e5+10;
vector<PII>f[N];
int l_t,r_t;
bool str[N];
int sum[N],fa[N],dep[N],son[N],top[N];
void dfs(int father,int cur)
{
    for(auto [v,len]:f[cur])
    {
        if(v==father) continue;
        dep[v]=dep[cur]+len;
        if(dep[v]>dep[l_t]) l_t=v;
        dfs(cur,v);
    }
}
int ans_2;
void dfs_1(int father,int cur)
{
    sum[cur]=1;
    for(auto [v,len]:f[cur])
    {
        if(v==father) continue;
        dep[v]=dep[cur]+len;
        fa[v]=cur;
        dfs_1(cur,v);
        sum[cur]+=sum[v];
        if(sum[v]>sum[son[cur]]) son[cur]=v;
    }
}
void dfs_2(int fcur,int cur)
{
    top[cur]=fcur;
    if(son[cur]) dfs_2(fcur,son[cur]);
    for(auto [v,len]:f[cur])
    {
        if(v==fa[cur]||v==son[cur]) continue;
        dfs_2(v,v);
    }
}
int lca(int l,int r)
{
    while(top[l]!=top[r])
    {
        if(dep[top[l]]>dep[top[r]]) l=fa[top[l]];
        else r=fa[top[r]];
    }
    return dep[l]<dep[r]?l:r;
}
int dis(int a,int b){return dep[a]+dep[b]-2*dep[lca(a,b)];}
void solve()
{
    int n,m;
    cin>>n>>m;
    while(m--)
    {
        int u,v,len;
        cin>>u>>v>>len;
        f[u].push_back({v,len});
        f[v].push_back({u,len});
    }
    dfs(0,1);
    r_t=l_t;
    dep[l_t]=0;
    dfs(0,l_t);
    swap(l_t,r_t);//俩遍dfs求树的俩个端点
    dfs_1(0,l_t);
    dfs_2(l_t,l_t);//树剖,用来求lca,lca用来求树上俩点之间的距离
//l_t是直径的一个端点,也是树根,r_t是树上直径的另一个端点
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(i==l_t||i==r_t) continue;
        ans=max(ans,min(dis(i,l_t),dis(i,r_t))+dep[r_t]);//计算答案然后取最大
    }
    cout<<ans<<'\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    int t;
    t=1;
    while(t--){solve();}
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值