您的位置:首页 > 其它

【GDSOI2017第三轮模拟】Travel Plan

2017-04-21 22:12 351 查看

Description



Sample Input

4

1 2

2 3

2 4

3 6

2 4

4 7

4 9

2

3 8

4 8

Sample Output

3

4



题解

首先观察一下这个范围,发现cost很大,但是value很小,所以我们考虑围绕value来dp

容易发现每一次ban掉的是一颗子树,也就是dfs序中的一段,所以我们可以考虑对前缀做一次dp,对后缀做一次dp,然后再合并

设f[i][j]表示我先在做到第i个点,获得j贡献所需的最小的代价,这个转移显然

现在考虑怎么合并

对于一个点x,它ban掉的就是dfs序中的t—-t+size[t]-1这些点,所以我们可以直接用两个指针来把前后缀合并一下

但是这样做理论时间复杂度很高,所以要注意一些优化

贴代码

const mc=4000000000;
var
a,b:array[0..1001,0..50000]of longword;
new,size,co,va,s1,s2:array[0..1005]of longint;
map:array[0..1005,0..1005]of integer;
i,j,k,l,n,x,y,now,o,q,t1,t2,ans:longint;
z,ct:int64;
function min(x,y:longword):longword;
begin
if x<y then exit(x) else exit(y);
end;
procedure dfs(x,y:longint);
var
i:longint;
begin
inc(now);
new[x]:=now;
size[now]:=1;
for i:=1 to map[x,0] do
if map[x,i]<>y then
begin
dfs(map[x,i],x);
size[new[x]]:=size[new[x]]+size[new[map[x,i]]];
end;
end;
begin
assign(input,'plan.in'); reset(input);
assign(output,'plan.out'); rewrite(output);
readln(n);
for i:=1 to n-1 do
begin
readln(x,y);
inc(map[x,0]);
map[x,map[x,0]]:=y;
inc(map[y,0]);
map[y,map[y,0]]:=x;
end;
dfs(1,0);
for i:=1 to n do readln(va[new[i]],co[new[i]]);
now:=0;
for i:=1 to 50000 do a[0,i]:=mc;
for i:=1 to n do
begin
now:=now+va[i];
s1[i]:=now;
for j:=now downto va[i] do
begin
a[i,j]:=a[i-1,j];
if a[i,j]=0 then a[i,j]:=mc;
a[i,j]:=min(a[i,j],a[i-1,j-va[i]]+co[i]);
end;
for j:=va[i]-1 downto 1 do
begin
a[i,j]:=a[i-1,j];
if a[i,j]=0 then a[i,j]:=mc;
end;
ct:=mc;
for j:=now downto 1 do
begin
if a[i,j]<ct then ct:=a[i,j];
a[i,j]:=ct;
end;
end;
now:=0;
for i:=1 to 50000 do b[n+1,i]:=mc;
for i:=n downto 1 do
begin
now:=now+va[i];
s2[i]:=now;
for j:=now downto va[i] do
begin
b[i,j]:=b[i+1,j];
if b[i,j]=0 then b[i,j]:=mc;
b[i,j]:=min(b[i,j],b[i+1,j-va[i]]+co[i]);
end;
for j:=va[i]-1 downto 1 do
begin
b[i,j]:=b[i+1,j];
if b[i,j]=0 then b[i,j]:=mc;
end;
ct:=mc;
for j:=now downto 1 do
begin
if b[i,j]<ct then ct:=b[i,j];
b[i,j]:=ct;
end;
end;
readln(q);
for o:=1 to q do
begin
readln(x,z);
x:=new[x];
y:=x+size[x];
x:=x-1;
t1:=0; t2:=s2[y];
ans:=0;
while t1<=s1[x] do
begin
while (a[x,t1]+b[y,t2]>z) and (t2>0) do dec(t2);
if a[x,t1]>z then break;
if t1+t2>ans then ans:=t1+t2;
inc(t1);
end;
writeln(ans);
end;
close(input); close(output);
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: