【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.
相关文章推荐
- [JZOJ5081]. 【GDSOI2017第三轮模拟】Travel Plan
- 【JZOJ5081】【GDSOI2017第三轮模拟】Travel Plan
- 【GDSOI2017第三轮模拟】Gift
- 【GDSOI2017第三轮模拟】Travel Plan 背包
- [JZOJ5082].【GDSOI2017第三轮模拟】Informatics Training
- 【GDSOI2017第三轮模拟】Informatics Training(码农,平衡树)
- 【JZOJ5082】【GDSOI2017第三轮模拟】Informatics Training
- 【jzoj5081】【GDSOI2017第三轮模拟】【Travel Plan】【动态规划】
- 【GDSOI2017模拟】Travel Plan
- [JZOJ5083].【GDSOI2017第三轮模拟】Gift
- 【jzoj5083】【GDSOI2017第三轮模拟】【Gift】【快速傅立叶变换】
- 【GDSOI2017第三轮模拟】Travel Plan(DP)
- JZOJ 5068. 【GDSOI2017第二轮模拟】树
- 【JZOJ5069】【GDSOI2017第二轮模拟】蛋糕
- JZOJ 【GDOI2017第三轮模拟day1】单旋
- 【JZOJ5073】【GDOI2017第三轮模拟day1】影魔
- 【GDSOI2017模拟4.13】炮塔 最小割
- 【GDSOI2017模拟4.13】炮塔(最小割)
- GDOI第三轮模拟总结
- 【jzoj5073】【GDOI2017第三轮模拟day1】【影魔】【数据结构】