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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章