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
posted @ 2017-01-19 20:09  GhoStreach  阅读(181)  评论(0编辑  收藏  举报