BZOJ 1999: [Noip2007]Core树网的核[dfs]

1.对于树中的任意一点,距离其最远的点一定是树的直径的某一端点
2.同一棵树的直径的中点相同(题目里给出来的,虽然不知道怎么用)
3.要求的一定在直径上,并且越长越好(不在直径上的点到端点的距离 直径上的点到端点的距离,都取较大的那个)
4.任意搞一条直径求出来的偏心距是一样的

随意求一条直径,然后抠出来枚举头尾处理一下
当前的这条链到别的点中最长的距离为max(到两端点的距离,到不在直径的点的最远距离)

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 500000
using namespace std;

struct edge{int to,v,next;}e[N*2+5];
int n,S,cnt,L,R,ans,head[N+5],que[N+5],fa[N+5],dis[N+5],dir[N+5];

inline void add(int x,int y,int z){
    e[++cnt]=(edge){y,z,head[x]};head[x]=cnt;
    e[++cnt]=(edge){x,z,head[y]};head[y]=cnt;
}

inline void bfs(int x,int opt){
    int h=0,t=1;
    que[1]=x;memset(dis,-1,sizeof(dis));dis[x]=0;
    while(h<=t){
        ++h;
        int u=que[h];
        for(int i=head[u];i;i=e[i].next)
            if(dis[e[i].to]==-1){
                dis[e[i].to]=dis[u]+e[i].v;
                if(opt==1) fa[e[i].to]=u;
                que[++t]=e[i].to;
            }
    }
}

void dfs(int x,int f){
    for(int i=head[x];i;i=e[i].next)
        if(e[i].to!=f&&!dir[e[i].to]){
            dis[e[i].to]=dis[x]+e[i].v;
            dfs(e[i].to,x);
        }
}

int main(){
    scanf("%d%d",&n,&S);
    for(int i=1,x,y,z;i<n;++i) {
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
    }
    L=1;bfs(L,0);for(int i=1;i<=n;++i) L=dis[i]>dis[L]?i:L;
    R=L;bfs(L,1);for(int i=1;i<=n;++i) L=dis[i]>dis[L]?i:L;
    for(int i=L;i;i=fa[i]) dir[i]=1;
    ans=1<<30;
    for(int p=L,q=L;p;p=fa[p]){
        while(fa[q]&&dis[p]-dis[fa[q]]<=S) q=fa[q];
        ans=min(ans,max(dis[q],dis[L]-dis[p]));
    }
    for(int i=L;i;i=fa[i])
        dis[i]=0,dfs(i,fa[i]);
    for(int i=1;i<=n;++i) ans=max(ans,dis[i]);
    printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值