到路径的距离就是到路径上的点最近的距离
首先看到最大值最小不难想到二分答案
下面的问题就是怎么判断,显然我们是不能穷举路径的
我们要找出消防路径的性质
仔细研究就会发现消防路径一定是树的直径的一段,这样必然最右
证明很简单,我们可以利用反证法解决,通过证明可以发现这个直径随便选一条就可以了
我们把树的直径拎出来,把直径上的点挂在直径下面(就相当于晾衣服一样……)
然后我们可以算出直径上每个点i的子树到i的最大距离,然后就很好处理了

  1 type node=record
  2        po,dis,next:longint;
  3      end;
  4 
  5 var q,d1,d2,p1,p2,p,f:array[0..300010] of longint;
  6     e:array[0..600010] of node;
  7     v:array[0..300010] of boolean;
  8     t,n,m,s,l,r,i,x,y,z,len,w:longint;
  9 
 10 function max(a,b:longint):longint;
 11   begin
 12     if a>b then exit(a) else exit(b);
 13   end;
 14 
 15 procedure add(x,y,z:longint);
 16   begin
 17     inc(len);
 18     e[len].po:=y;
 19     e[len].dis:=z;
 20     e[len].next:=p[x];
 21     p[x]:=len;
 22   end;
 23 
 24 procedure dfs(x:longint);
 25   var i,y:longint;
 26   begin
 27     v[x]:=true;
 28     i:=p[x];
 29     while i<>0 do
 30     begin
 31       y:=e[i].po;
 32       if not v[y] then
 33       begin
 34         dfs(y);
 35         if d1[y]+e[i].dis>d1[x] then
 36         begin
 37           d2[x]:=d1[x];
 38           p2[x]:=p1[x]; //p1,p2记录的是这棵子树最长次长延伸的方向
 39           d1[x]:=d1[y]+e[i].dis;
 40           p1[x]:=i;
 41         end
 42         else if d1[y]+e[i].dis>d2[x] then
 43         begin
 44           d2[x]:=d1[y]+e[i].dis;
 45           p2[x]:=i;
 46         end;
 47       end;
 48       i:=e[i].next;
 49     end;
 50     if d1[x]+d2[x]>d1[w]+d2[w] then w:=x;
 51   end;
 52 
 53 procedure dfss(x:longint);
 54   var i,y:longint;
 55   begin
 56     i:=p[x];
 57     v[x]:=true;
 58     while i<>0 do
 59     begin
 60       y:=e[i].po;
 61       if not v[y] then
 62       begin
 63         dfss(y);
 64         f[x]:=max(f[x],f[y]+e[i].dis);
 65       end;
 66       i:=e[i].next;
 67     end;
 68   end;
 69 
 70 procedure getl(x:longint);
 71   begin
 72     if p1[x]<>0 then getl(e[p1[x]].po);
 73     inc(t); q[t]:=x; v[x]:=true;
 74   end;
 75 
 76 function check(len:longint):boolean;
 77   var l,r,w:longint;
 78   begin
 79     l:=1;
 80     r:=t;
 81     w:=f[q[1]];
 82     while (l<t) and (w+d1[q[l+1]]<=len) do  //在满足最长距离不超过len的情况下使路径尽可能短
 83     begin
 84       inc(l);
 85       w:=max(w,f[q[l]]-d1[q[l]]);
 86     end;
 87     w:=f[q[t]]+d1[q[t]];
 88     while (r>l) and (w-d1[q[r-1]]<=len) do
 89     begin
 90       dec(r);
 91       w:=max(w,f[q[r]]+d1[q[r]]);
 92     end;
 93     if d1[q[r]]-d1[q[l]]<=s then exit(true)
 94     else exit(false);
 95   end;
 96 
 97 begin
 98   readln(n,s);
 99   for i:=1 to n-1 do
100   begin
101     readln(x,y,z);
102     add(x,y,z);
103     add(y,x,z);
104   end;
105   dfs(1);
106   fillchar(v,sizeof(v),false);
107   getl(w);
108   x:=w; i:=p2[x];
109   while i<>0 do
110   begin
111     y:=e[i].po;
112     inc(t); q[t]:=e[i].po; v[y]:=true;
113     d1[y]:=d1[x]+e[i].dis;  //把直径提出来作为一条链,d1相当于到链头的距离
114     i:=p1[y]; x:=y;
115   end;
116   r:=d1[x];
117   for i:=1 to t do
118   begin
119     x:=q[i];
120     dfss(x);
121     l:=max(l,f[x]); //f处理的是子树最深距离
122   end;
123   if s<d1[q[t]] then
124   begin
125     while l<=r do
126     begin
127       m:=(l+r) shr 1;
128       if check(m) then r:=m-1
129       else l:=m+1;
130     end;
131   end;
132   writeln(l);
133 end.
View Code

 

posted on 2015-03-16 13:15  acphile  阅读(131)  评论(0编辑  收藏  举报