P1099 树网的核

本文探讨了一种解决树网核问题的方法,首先找到树的直径,然后通过在直径上进行尺取操作得出最终答案。作者提到该问题在数据较小的情况下容易解决,但在更大规模的数据如bzoj上的1e5规模可能会更具挑战性。文章最后提供了实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

思路:先找出树的直径,然后在直径上尺取得到最终结果。
这个题数据很水,听说bzoj上有加强到1e5的数据,我是想过了洛谷的题之后在bzoj上试试的,但谁知没机会了。
上代码:

//#pragma GCC optimize (2)


#include<cstdio>
#include<iostream>
#include<cmath>
#include<functional>
#include<cstring>
#include<string>
#include<cstdlib>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#include<stack>
#include<vector>
#include<sstream>
#include<list>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn= 2e5+10;
const ll mod=6662333;
const int N=500;
struct node
{
    int to,len,next;
} p[2*N];
int head[N];
int n,s;
int cnt;
void add(int from,int to,int len)
{
    p[cnt].to=to;
    p[cnt].len=len;
    p[cnt].next=head[from];
    head[from]=cnt++;
}
int vis[N];
struct L
{
    int id,len;
};
int ans,maxl;
int bfs(int x)
{
    L now;
    queue<L>q;
    now={x,0};
    q.push(now);
    ans=0,maxl=-1;
    while(!q.empty())
    {
        now=q.front();q.pop();
        vis[now.id]=1;
        if(now.len>maxl)
        {
            ans=now.id;
            maxl=now.len;
        }
        for(int i=head[now.id];i!=-1;i=p[i].next)
        {
            if(!vis[p[i].to])
                q.push({p[i].to,now.len+p[i].len});
        }
    }
    return ans;
}
int link[N];
int cntlink;
int flag=0;
void dfs(int s,int t)
{
    link[++cntlink]=s;
    if(flag)return;
    if(s==t)
    {
        flag=1;
        return ;
    }
    vis[s]=1;
    for(int i=head[s];i!=-1;i=p[i].next)
    {
        if(!vis[p[i].to])
        {
            dfs(p[i].to,t);
            if(flag)return;
            cntlink--;
        }
    }
}
int maxL[N];
int pl[N];
int main()
{
    cin>>n>>s;
    int u,v,w;
    memset(head,-1,sizeof head);
    for(int i=0;i<n-1;i++)
    {
        cin>>u>>v>>w;
        add(u,v,w);
        add(v,u,w);
    }
    memset(vis,0,sizeof vis);
    u=bfs(1);
    memset(vis,0,sizeof vis);
    v=bfs(u);
    memset(vis,0,sizeof vis);
    dfs(u,v);
    memset(vis,0,sizeof vis);
    for(int i=1;i<=cntlink;i++)vis[link[i]]=1;
    for(int i=1;i<=cntlink;i++)
    {
        bfs(link[i]);
        maxL[i]=maxl;
    }
    pl[1]=0;
    for(int i=1;i<=cntlink;i++)
        for(int j=head[link[i]];j!=-1;j=p[j].next)
            if(p[j].to==link[i+1])
            {
                pl[i+1]=p[j].len+pl[i];
                break;
            }
    int fans=INF,l=1,r=1;
    while(r<=cntlink)
    {
        while(l<r&&pl[r]-pl[l]>s)l++;
        while(r+1<=cntlink&&pl[r+1]-pl[l]<=s)r++;
        int tmp=0;
        for(int i=1;i<l;i++)tmp=max(tmp,maxL[i]+pl[l]-pl[i]);
        for(int i=l;i<=r;i++)tmp=max(tmp,maxL[i]);
        for(int i=r+1;i<=cntlink;i++)tmp=max(tmp,maxL[i]+pl[i]-pl[r]);
        fans=min(fans,tmp);
        r++;
    }
    cout<<fans<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值