bzoj 2282 消防

Written with StackEdit.

Description

某个国家有\(n\)个城市,这\(n\)个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为\(z_i(z_i<=1000)\)

这个国家的人对火焰有超越宇宙的热情,所以这个国家最兴旺的行业是消防业。由于政府对国民的热情忍无可忍(大量的消防经费开销)可是却又无可奈何(总统竞选的国民支持率),所以只能想尽方法提高消防能力。

现在这个国家的经费足以在一条边长度和不超过\(s\)的路径(两端都是城市)上建立消防枢纽,为了尽量提高枢纽的利用率,要求其他所有城市到这条路径的距离的最大值最小。

你受命监管这个项目,你当然需要知道应该把枢纽建立在什么位置上。

Input

输入包含\(n\)行:
\(1\)行,两个正整数\(n\)\(s\),中间用一个空格隔开。其中\(n\)为城市的个数,\(s\)为路径长度的上界。设结点编号以此为\(1,2,……,n\)
从第\(2\)行到第\(n\)行,每行给出\(3\)个用空格隔开的正整数,依次表示每一条边的两个端点编号和长度。例如,\(“2\) \(4\) \(7”\)表示连接结点\(2\)\(4\)的边的长度为\(7\)

Output

输出包含一个非负整数,即所有城市到选择的路径的最大值,当然这个最大值必须是所有方案中最小的。

Sample Input

【样例输入1】
5 2
1 2 5
2 3 2
2 4 4
2 5 3

【样例输入2】
8 6
1 3 2
2 3 2
3 4 6
4 5 3
4 6 4
4 7 2
7 8 3

Sample Output

【样例输出1】

5
【样例输出2】

5

HINT

对于\(100\%\)的数据,\(n<=300000\),边长\(<=1000\)

Solution

  • 有一个性质:这样的路径一定是直径上的某一段.
  • 那么先通过两次\(bfs\)找出直径,二分答案.
  • 根据二分的答案在直径两侧向内取,取出后验证长度是否小于等于\(s\).
#include<bits/stdc++.h>
using namespace std;
typedef long long LoveLive;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>'9'||jp<'0')&&jp!='-')
        jp=getchar();
    if (jp=='-')
        {
            fh=-1;
            jp=getchar();
        }
    while (jp>='0'&&jp<='9')
        {
            out=out*10+jp-'0';
            jp=getchar();
        }
    return out*fh;
}
const int MAXN=3e5+10;
int n,s;
int cnt=0,head[MAXN];
int nx[MAXN<<1],to[MAXN<<1],val[MAXN<<1];
inline void add(int u,int v,int w)
{
    ++cnt;
    to[cnt]=v;
    nx[cnt]=head[u];
    val[cnt]=w;
    head[u]=cnt;
}
int dis[MAXN],pre[MAXN];
int marked[MAXN];
void bfs(int rt)
{
    memset(dis,-1,sizeof dis);
    dis[rt]=0;
    queue<int> q;
    q.push(rt);
    while(!q.empty())
        {
            int u=q.front();
            q.pop();
            for(int i=head[u];i;i=nx[i])
                {
                    int v=to[i];
                    if(dis[v]!=-1)
                        continue;
                    pre[v]=u;
                    if(marked[v])
                        dis[v]=dis[u];
                    else
                        dis[v]=dis[u]+val[i];
                    q.push(v);
                }
        }
}
int top=0,st[MAXN];
int check(int d)
{
    int l=1,r=top;
    while(st[1]-st[l+1]<=d && l<=top)
        ++l;
    while(st[r-1]<=d && r>=1)
        --r;
    return st[l]-st[r]<=s;
}
int main()
{
    n=read(),s=read();
    for(int i=1;i<n;++i)
        {
            int u=read(),v=read(),w=read();
            add(u,v,w);
            add(v,u,w);
        }
    int rt=0,x=0;
    bfs(1);
    for(int i=1;i<=n;++i)
        if(dis[rt]<dis[i])
            rt=i;
    bfs(rt);
    for(int i=1;i<=n;++i)
        if(dis[x]<dis[i])
            x=i;//from rt to x
    int L=0,R=dis[x];
    st[++top]=dis[x];
    marked[x]=1;
    while(x!=rt)
        {
            st[++top]=dis[pre[x]];
            x=pre[x];
            marked[x]=1;
        }
    bfs(x);
    for(int i=1;i<=n;++i)
        L=max(L,dis[i]);
    if(s<R)
        {
            while(L<=R)
                {
                    int mid=(L+R)>>1;
                    if(check(mid))
                        R=mid-1;
                    else
                        L=mid+1;
                }
        }
    printf("%d\n",L);
    return 0;
}

参考了hzwer的blog.

猜你喜欢

转载自www.cnblogs.com/jklover/p/10062026.html
今日推荐