BZOJ1999(Noip2007)[Core树网的核]--最长链+DFS大法

【链接】
bzoj1999

【题目大意】
好像是加强版啊

这里博主就补个图吧。

这里写图片描述

【解题报告】
Dfs大法好啊

其实这题要仔细思考,思路清晰后就可以得到两个结论。

(1)对于树中的任意一点,距离其最远的点一定是树的直径的某一端点。

(2)所有的直径是等价的,即任意一条所能求出的该最小偏心距相等。

所以先求一遍最长链。

然后先求链中的最小偏心距,最小偏心距的路径肯定是经过核心的(除非是一个点)。

然后因为最小偏心距可能受其他直径影响,所以再求一遍路径到其他点中的最大距离,挑小的,就行了。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=500005,maxm=1000005,INF=((1<<30)-1)+1;
int n,S,tot,ans,L,R,fa[maxn],dst[maxn],lnk[maxn],w[maxm],son[maxm],nxt[maxm];
bool vis[maxn];
inline char nc()
{
    static char buf[100000],*l,*r;
    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
    if (l==r) return EOF; return *l++;
}
inline int Read()
{
    int res=0; char ch=nc();
    while (ch<'0'||ch>'9') ch=nc();
    while (ch>='0'&&ch<='9') res=res*10+ch-48,ch=nc();
    return res;
}
void Add(int x,int y,int z) {w[++tot]=z; son[tot]=y; nxt[tot]=lnk[x]; lnk[x]=tot;}
void Dfs(int x,int Fa)
{
    fa[x]=Fa;
    for (int j=lnk[x]; j; j=nxt[j])
     if (son[j]!=Fa&&!vis[son[j]]) dst[son[j]]=dst[x]+w[j],Dfs(son[j],x);
}
void Getline()
{
    memset(dst,0,sizeof(dst));
    Dfs(1,0); R=0;
    for (int i=1; i<=n; i++)
     if (dst[i]>dst[R]) R=i;
    memset(dst,0,sizeof(dst));
    Dfs(R,0); L=0;
    for (int i=1; i<=n; i++)
     if (dst[i]>dst[L]) L=i;
}
void Solve()
{
    int i=L,j=L; ans=INF;
    for (; i; i=fa[i])
    {
        while (fa[j]&&dst[i]-dst[fa[j]]<=S) j=fa[j];
        ans=min(ans,max(dst[j],dst[L]-dst[i]));
    }
    for (i=L; i; i=fa[i]) vis[i]=1;
    for (i=L; i; i=fa[i]) dst[i]=0,Dfs(i,fa[i]);
    for (int i=1; i<=n; i++) ans=max(ans,dst[i]);
    printf("%d\n",ans);
}
int main()
{
    freopen("1999.in","r",stdin);
    freopen("1999.out","w",stdout);
    n=Read(); S=Read(); tot=0;
    memset(lnk,0,sizeof(lnk));
    for (int i=1,x,y,z; i<n; i++) x=Read(),y=Read(),z=Read(),Add(x,y,z),Add(y,x,z);
    Getline();
    Solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值