BZOJ2282 SDOI2011 消防 BFS+单调队列

题意:给定一棵树,求树上一条长度不大于S的路径,使得树上所有点到该路径的最大距离最小。

题解:

首先,所求路径一定在树的直径上,否则我们总可以用树的直径来扩展出更大的最大距离。

设fi为i为路径左端点时,直径的右端点到i的距离;gi为i为路径右端点时,直径的左端点到i的距离;hi为i的与直径没有交集的子树中,到i的最远距离。对于一个确定的路径ab,显然我们有\[Dist = \max (\max ({f_l},{g_r}),\max \{ {h_i}\} ),i \in [l,r]\]

然后用双端队列来维护后面h的最大值即可

——————————————————————————————

这个题到这里就算做完了,但是有个问题……我不会求树的直径QAQ

所以这里说一下怎么求树的直径:首先随便确定一个根Root,BFS出其他所有节点到Root的距离d[i],找出s使得d[s]最大,令Root=s,再跑一遍BFS,然后找出t使得d[t]最大,那么s到t的路径就是这棵树的直径。证明可以看这里

#include <cstdio>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;

const int MAXN=300000+2;
struct Hash{
    int u,w;
    Hash *Next;
    Hash(){}
    Hash(int _u,int _w,Hash *_Next):u(_u),w(_w),Next(_Next){}
}*Tab[MAXN],Mem[2*MAXN];
int N,S,F=1,T,f[MAXN],g[MAXN],h[MAXN],Fa[MAXN],Flag[MAXN],Link[MAXN],C,Tmp[MAXN],Mark[MAXN],dq[MAXN],L,R,Ans=INT_MAX,cnt;
queue<int> q;

void Insert(int u,int v,int w){ Tab[u]=&(Mem[cnt++]=Hash(v,w,Tab[u]));}

int BFS(int s,int t){
    int Len=-1;
    q.push(s),g[s]=0,Fa[s]=s,Flag[s]=t;

    int x;
    while(!q.empty()){
        x=q.front(),q.pop();
        for(Hash *p=Tab[x];p;p=p->Next)
            if(Flag[p->u]!=t){
                g[p->u]=g[x]+p->w,Flag[p->u]=t,Fa[p->u]=x;
                q.push(p->u),Len=max(Len,g[p->u]);
            }
    }
    return Len;
}

int main(){
    cin >> N >> S;
    for(int i=1,u,v,w;i<N;i++){
        scanf("%d %d %d",&u,&v,&w);
        Insert(u,v,w),Insert(v,u,w);
    }

    BFS(F,1);
    for(int i=1;i<=N;i++)
        if(g[i]>g[F]) F=i;
    BFS(F,2);
    for(int i=1;i<=N;i++)
        if(g[i]>g[T]) T=i;
    Link[++C]=T;
    do{
        T=Fa[T],Link[++C]=T,Flag[T]=3;
    }while(T!=F);

    for(int i=1;i<=C;i++) f[i]=g[Link[1]]-g[Link[i]];
    for(int i=1;i<=C;i++) Tmp[i]=g[Link[i]];
    for(int i=1;i<=C;i++) h[i]=BFS(Link[i],3);
    for(int i=1;i<C;i++) g[i]=Tmp[i];
    g[C]=0;

    for(int l=1,r=0;l<=C;l++){
        while(r<C && f[r+1]-f[l]<=S){
            r++;
            while(L<=R && dq[R]<h[r]) R--;
            dq[++R]=h[r],Mark[R]=r;
        }
        Ans=min(Ans,max(max(f[l],g[r]),dq[L]));
        if(Mark[L]<=l) L++;
    }
    cout << Ans << endl;

    return 0;
}
View Code

 

posted @ 2017-03-11 17:22  WDZRMPCBIT  阅读(149)  评论(0编辑  收藏  举报