好题
显然是分数规划,二分答案之后我们要找是否存在一条边数在[l,u]长度和为正的路径
可以用树的分治来解决这个问题
我们假设当前处理的是过点root的路径
显然我们不好像之前男人八题里先算出所有答案,然后再剔除不合法的
这里我们的统计方法是依次处理每个子树,算这个子树中的从根到某个节点的路径和之前处理的子树的路径能产生的最大值
这样就能保证路径过root且不重不漏
然后不难想到维护w[s]表示处理到当前子树前边数为s的路径长度和的最大值,处理完当前子树更新w[]
考虑能产生的最大合法路径我们bfs当前子树,由于从子树根到节点的边数是逐渐增加的
不难想到维护一个单调队列来解决,具体维护见程序
由于这道题时限比较紧,如果我们先二分然后用树分治判定是否合法,非常耗时
思考一下我们的流程,我们找到树的重心后要处理过重心的路径
我们完全可以在这时内二分得出过重心的最优值然后向下分治时,这个最优值就成了以后的下界
这样不断提高下界可以快不少
还有一些优化细节见程序

  1 const eps=0.0001;
  2 type node=record
  3        po,next,len:longint;
  4      end;
  5 
  6 var e:array[0..200010] of node;
  7     fa,dep,p,f,s,q,qq:array[0..100010] of longint;
  8     d,w,g:array[0..100010] of double;
  9     v:array[0..100010] of boolean;
 10     md,tot,n,root,i,l,u,len,x,y,z:longint;
 11     h,r,m,ans,lim:double;
 12 
 13 function max(a,b:longint):longint;
 14   begin
 15     if a>b then exit(a) else exit(b);
 16   end;
 17 
 18 function maxx(a,b:double):double;
 19   begin
 20     if a>b then exit(a) else exit(b);
 21   end;
 22 
 23 procedure add(x,y,z:longint);
 24   begin
 25     inc(len);
 26     e[len].po:=y;
 27     e[len].len:=z;
 28     e[len].next:=p[x];
 29     p[x]:=len;
 30   end;
 31 
 32 procedure getroot(x,fa:longint);  //找重心
 33   var i,y:longint;
 34   begin
 35     i:=p[x];
 36     f[x]:=0;
 37     s[x]:=1;
 38     while i<>0 do
 39     begin
 40       y:=e[i].po;
 41       if not v[y] and (y<>fa) then
 42       begin
 43         getroot(y,x);
 44         s[x]:=s[x]+s[y];
 45         f[x]:=max(f[x],s[y]);
 46       end;
 47       i:=e[i].next;
 48     end;
 49     f[x]:=max(f[x],tot-s[x]);
 50     if f[x]<f[root] then root:=x;
 51   end;
 52 
 53 function calc(x:longint):boolean;
 54   var f,r,i,y,j,h,t:longint;
 55   begin
 56     f:=1;  r:=1;    q[1]:=x;
 57     dep[x]:=1;
 58     fa[x]:=0;
 59     h:=1; t:=0;
 60     j:=md;  //这个优化使数据某个点快了十倍,md表示之前处理的子树最深的链的深度
 61     while f<=r do
 62     begin
 63       x:=q[f];
 64       g[dep[x]]:=maxx(g[dep[x]],d[x]);
 65       while (j>=0) and (j+dep[x]>=l) do  //倒序入队,保证满足路径边数下界,维护单调降队列
 66       begin
 67         while (h<=t) and (w[j]>w[qq[t]]) do dec(t);
 68         inc(t);
 69         qq[t]:=j;
 70         dec(j);
 71       end;
 72       while (h<=t) and (qq[h]+dep[x]>u) do inc(h);  //端头出队满足上界
 73       if (h<=t) and (w[qq[h]]+d[x]>=0) then
 74       begin
 75         md:=max(md,dep[x]);
 76         exit(true);
 77       end;
 78       if dep[x]<u then
 79       begin
 80         i:=p[x];
 81         while i<>0 do
 82         begin
 83           y:=e[i].po;
 84           if (fa[x]<>y) and not v[y] then
 85           begin
 86             fa[y]:=x;
 87             dep[y]:=dep[x]+1;
 88             d[y]:=d[x]+e[i].len-m;
 89             inc(r);
 90             q[r]:=y;
 91           end;
 92           i:=e[i].next;
 93         end;
 94       end;
 95       inc(f);
 96     end;
 97     md:=max(md,dep[x]);
 98     for i:=1 to dep[x] do
 99       w[i]:=maxx(w[i],g[i]);
100     exit(false);
101   end;
102 
103 function check(x:longint):boolean;
104   var i,y:longint;
105   begin
106     md:=1;
107     check:=false;
108     i:=p[x];
109     while i<>0 do
110     begin
111       y:=e[i].po;
112       if not v[y] then
113       begin
114         d[y]:=e[i].len-m;
115         if calc(y) then
116         begin
117           check:=true;
118           break;
119         end;
120       end;
121       i:=e[i].next;
122     end;
123     for i:=1 to md do
124     begin
125       w[i]:=-1000000007;
126       g[i]:=-1000000007;
127     end;
128   end;
129 
130 procedure work(x:longint);
131   var i,y:longint;
132   begin
133     v[x]:=true;
134     h:=ans;
135     r:=lim;
136     while r-h>eps do
137     begin
138       m:=(h+r)/2;
139       if check(x) then
140       begin
141         ans:=m;
142         h:=m;
143       end
144       else r:=m;
145     end;
146     i:=p[x];
147     while i<>0 do
148     begin
149       y:=e[i].po;
150       if not v[y] then
151       begin
152         tot:=s[y];
153         root:=0;
154         getroot(y,0);
155         if s[y]>l then work(root);
156       end;
157       i:=e[i].next;
158     end;
159   end;
160 
161 begin
162   f[0]:=2147483647;
163   readln(n);
164   readln(l,u);
165   for i:=1 to n-1 do
166   begin
167     readln(x,y,z);
168     add(x,y,z);
169     add(y,x,z);
170     if lim<z then lim:=z;
171   end;
172   for i:=1 to u do
173   begin
174     w[i]:=-1000000007;
175     g[i]:=-1000000007;
176   end;
177   root:=0;
178   tot:=n;
179   getroot(1,0);
180   work(root);
181   writeln(ans:0:3);
182 end.
View Code

 

posted on 2015-02-25 18:14  acphile  阅读(131)  评论(0编辑  收藏  举报