zoukankan      html  css  js  c++  java
  • BZOJ2282:[SDOI2011]消防

    Description

    某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=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。

    题解:

    有一个结论:树的任意一条直径上一定存在最优路径,即使树的直径不止一条。

    这样,我们可以两边DFS求出树的一条直径,然后把树的直径上的点排成队列,记录从这些点向外(即不沿直径的两个方向)所能走到的最远距离。

    让左右端点在队列上移动,表示所选的区间。当右端点确定时,左端点要尽量靠左(即路径要尽量长)才更优,但长度不能超过限定。

    选择这样的一条路径的最远距离即为左端点到直径一端的距离、路径上点向外走出的最远距离(我用了线段树,事实上可以利用直径的性质O(1)记录)、右端点到直径另一端的距离的最大值。

    代码:

     1 uses math;
     2 var
     3   i,j,k,l,n,m,s,rt,len,nn,cnt,ans:longint;
     4   b:array[0..600001,0..2]of longint;
     5   dis,c,dis2,dis3,fx,a,lb:array[0..300001]of longint;
     6   t:array[0..600001,-2..2]of longint;
     7 procedure ss(x,fa:longint);
     8 var i:longint;
     9 begin
    10   i:=c[x];
    11   while i>0 do
    12   begin
    13     if b[i,1]<>fa then
    14     begin dis[b[i,1]]:=dis[x]+b[i,0]; ss(b[i,1],x); end;
    15     i:=b[i,2];
    16   end;
    17 end;
    18 procedure ss2(x,fa:longint);
    19 var i:longint;
    20 begin
    21   i:=c[x];
    22   while i>0 do
    23   begin
    24     if b[i,1]<>fa then
    25     begin
    26       dis[b[i,1]]:=dis[x]+b[i,0];
    27       ss2(b[i,1],x);
    28       if dis2[b[i,1]]+b[i,0]>dis2[x] then
    29       begin dis2[x]:=dis2[b[i,1]]+b[i,0]; fx[x]:=i; end;
    30     end;
    31     i:=b[i,2];
    32   end;
    33   i:=c[x];
    34   while i>0 do
    35   begin
    36     if(b[i,1]<>fa)and(i<>fx[x])then
    37     dis3[x]:=max(dis3[x],dis2[b[i,1]]+b[i,0]);
    38     i:=b[i,2];
    39   end;
    40 end;
    41 procedure ss3(x:longint);
    42 var i:longint;
    43 begin
    44   inc(nn); a[nn]:=dis3[x]; lb[nn]:=x;
    45   if fx[x]>0 then ss3(b[fx[x],1]);
    46 end;
    47 procedure build(l,r,fa:longint);
    48 var x:longint;
    49 begin
    50   inc(cnt); x:=cnt;
    51   t[x,1]:=l; t[x,2]:=r;
    52   if t[x,1]=t[fa,1] then t[fa,-1]:=x else t[fa,-2]:=x;
    53   if l=r then begin t[x,0]:=a[l]; exit; end;
    54   build(l,(l+r)div 2,x); build((l+r)div 2+1,r,x);
    55   t[x,0]:=max(t[t[x,-1],0],t[t[x,-2],0]);
    56 end;
    57 function qq(x,l,r:longint):longint;
    58 var ll,rr:longint;
    59 begin
    60   ll:=t[x,1]; rr:=t[x,2];
    61   if(ll=l)and(rr=r)then exit(t[x,0]);
    62   if r<=(ll+rr)div 2 then exit(qq(t[x,-1],l,r));
    63   if l>(ll+rr)div 2 then exit(qq(t[x,-2],l,r));
    64   exit(max(qq(t[x,-1],l,(ll+rr)div 2),qq(t[x,-2],(ll+rr)div 2+1,r)));
    65 end;
    66 begin
    67   readln(n,s);
    68   for i:=2 to n do
    69   begin
    70     readln(j,k,l);
    71     inc(m); b[m,1]:=k; b[m,0]:=l; b[m,2]:=c[j]; c[j]:=m;
    72     inc(m); b[m,1]:=j; b[m,0]:=l; b[m,2]:=c[k]; c[k]:=m;
    73   end;
    74   ss(1,0); rt:=1;
    75   for i:=2 to n do if dis[i]>dis[rt] then rt:=i;
    76   dis[rt]:=0; ss2(rt,0); ss3(rt); len:=dis2[rt];
    77   build(1,nn,0);
    78   j:=1; ans:=maxlongint;
    79   for i:=1 to nn do
    80   begin
    81     while dis[lb[i]]-dis[lb[j]]>s do inc(j);
    82     ans:=min(ans,max(max(dis[lb[j]],dis2[lb[i]]),qq(1,j,i)));
    83   end;
    84   writeln(ans);
    85 end.
    View Code
  • 相关阅读:
    【HDU
    写个shell脚本依次运行每个程序半小时
    Windows10 + Visual Studio 2017环境为C++工程安装使用ZMQ
    【UVALive
    【Gym
    【最短路算法】Dijkstra+heap和SPFA的区别
    【Gym 100812C】Story of Princess (走完图所有边)
    【C++】VS2015/VS2017连接Mysql数据库教程
    博客园设置Google-code-prettify渲染代码高亮
    【QML与C++混合编程】用QVariantList传递数组类型成员
  • 原文地址:https://www.cnblogs.com/GhostReach/p/6308650.html
Copyright © 2011-2022 走看看