消防(mindist)

来源:互联网 发布:最火淘宝浏览单app软件 编辑:程序博客网 时间:2024/04/27 19:58
消防(mindist)
【问题描述】
某个国家有n 个城市,这n 个城市中任意两个都连通且有唯一一条路径,每
条连通两个城市的道路的长度为zi(zi<=1000)。
这个国家的人对火焰有超越宇宙的热情,所以这个国家最兴旺的行业是消防
业。由于政府对国民的热情忍无可忍(大量的消防经费开销)可是却又无可奈何
(总统竞选的国民支持率),所以只能想尽方法提高消防能力。
现在这个国家的经费足以在一条边长度和不超过s 的路径(两端都是城市)
上建立消防枢纽,为了尽量提高枢纽的利用率,要求其他所有城市到这条路径的
距离的最大值最小。
你受命监管这个项目,你当然需要知道应该把枢纽建立在什么位置上。
【输入格式】
输入包含n 行:
第1 行,两个正整数n 和s,中间用一个空格隔开。其中n 为城市的个数,
s 为路径长度的上界。设结点编号以此为1,2,……,n。
从第2 行到第n 行,每行给出3 个用空格隔开的正整数,依次表示每一条边的
两个端点编号和长度。例如,“2 4 7”表示连接结点2 与4 的边的长度为7。
【输出格式】
输出包含一个非负整数,即所有城市到选择的路径的最大值,当然这个最大
值必须是所有方案中最小的。

【样例输入1】

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

2 3 2
3 4 6
4 5 3
4 6 4
4 7 2
7 8 3
【样例输出2】
5
【数据规模和约定】
对于20%的数据,n<=300。
对于50%的数据,n<=3000。
对于100%的数据,n<=300000,边长小等于1000。


可以证明,建立枢纽的路必然在树的直径(即树的最长链)上

这个问题明显具有单调性,如果3可以,那4也可以

所以可以二分答案,问题就变为已知一个答案,如何验证是否可行

首先预处理一下直径上的点的不在直径上的最长链,其中最长的即为答案下界

然后贪心处理即可,从链的底部出发向上,在不超过答案的情况下就不把边删除,之后能删除多少边就删除多少边,删除完判断合法不合法即可


program mindist;var  mid,l,r,bot,top,max,tot,n,s,i,j,k,u,v,c:longint;  val,oth,father,dis,root:array [0..300001] of longint;  next,cost,point:array [0..600001] of longint;  line:array [0..300001] of boolean;procedure connect (u,v,c:longint);inline;begin  inc(tot);  point[tot]:=v;  cost[tot]:=c;  next[tot]:=root[u];  root[u]:=tot;end;procedure search (now:longint);var  i:longint;begin  if dis[now]>dis[max] then max:=now;  i:=root[now];  while i<>0 do    begin      if point[i]<>father[now] then        begin          dis[point[i]]:=dis[now]+cost[i];          father[point[i]]:=now;          val[point[i]]:=cost[i];          search(point[i]);        end;      i:=next[i];    end;end;procedure dfs (now:longint);var  i:longint;begin  i:=root[now];  while i<>0 do    begin      if point[i]<>father[now] then        begin          dfs(point[i]);          if not line[point[i]] then            if oth[point[i]]+cost[i]>oth[now] then              oth[now]:=oth[point[i]]+cost[i];        end;      i:=next[i];    end;  if oth[now]>max then max:=oth[now];end;function ok (ans:longint):boolean;var  i,k,now:longint;begin  i:=bot;  while (i<>top)and(dis[bot]-dis[father[i]]<=ans) do i:=father[i];  now:=0;  while i<>top do    begin      if now+val[i]>s then break;      now:=now+val[i];      i:=father[i];    end;  if dis[i]>ans then exit(false)                else exit(true);end;begin  assign(input,'mindist.in');  reset(input);  assign(output,'mindist.out');  rewrite(output);  read(n,s);  for i:=1 to n-1 do    begin      read(u,v,c);      connect(u,v,c);      connect(v,u,c);    end;  fillchar(father,sizeof(father),0);  fillchar(dis,sizeof(dis),0);  max:=1;  search(1);  top:=max;  fillchar(father,sizeof(father),0);  fillchar(dis,sizeof(dis),0);  search(top);  bot:=max;  fillchar(line,sizeof(line),false);  i:=bot;  repeat    line[i]:=true;    i:=father[i];  until i=0;  max:=0;  dfs(top);  l:=max;  r:=300000;  while l<>r do    begin      mid:=(l+r) div 2;      if ok(mid) then r:=mid                 else l:=mid+1;    end;  writeln(l);  close(input);  close(output);end.