【GDSOI2017第三轮模拟】Travel Plan

来源:互联网 发布:内涵段子ios源码 编辑:程序博客网 时间:2024/05/03 16:58

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.
0 0
原创粉丝点击