花花的聚会

题目描述 花花住在H 国。H 国有n 个城市,其中1 号城市为其首都。城市间有n-1
条单向道路。从任意一个城市出发,都可以沿着这些单向道路一路走到首都。事实上,从任何一个城市走到首都的路径是唯一的。
过路并不是免费的。想要通过某一条道路,你必须使用一次过路券。H 国一共有m 种过路券,每张过路券以三个整数表示:v k w:你可以在城市v
以价格w 买到一张过路券。这张券可以使用k 次。这意味着,拿着这张券通过了k 条道路之后,这张券就不能再使用了。
请注意你同一时间最多只能拥有最多一张过路券。但你可以随时撕掉手中已有的过路券,并且在所在的城市再买一张。 花花家在首都。他有q
位朋友,他希望把这些朋友们都邀请到他家做客。所以他想要知道每位朋友要花多少路费。他的朋友们都很聪明,永远都会选择一条花费最少的方式到达首都。
花花需要准备晚餐去了,所以他没有时间亲自计算出朋友们将要花费的路费。你可以帮帮他么?

输入 输入的第一行包含两个空格隔开的整数n 和m,表示H 国的城市数量和过路券的种数。 之后的n-1行各自包含两个数ai
和bi,代表城市ai到城市bi间有一条单向道路。 之后的m 行每行包括三个整数vi; ki 和wi,表示一种过路券。
下一行包含一个整数q,表示花花朋友的数量。 之后的q 行各自包含一个整数,表示花花朋友的所在城市。

输出 输出共q 行,每一行代表一位朋友的路费。

样例输入 7 7
3 1
2 1
7 6
6 3
5 3
4 3
7 2 3
7 1 1
2 3 5
3 6 2
4 2 4
5 3 10
6 1 20
3
5 6 7
样例输出
10
22
5
提示
对于第一位朋友,他在5 号城市只能购买一种过路券,花费10 元并且可以使用3次。这足够他走到首都,因此总花费是10 元。

对于第二位朋友,他在6 号城市只能购买20 元的过路券,并且只能使用一次。之后,他可以在3 号城市购买2 元,可以使用3
次的过路券走到首都。总花费是22 元。

对于第三位朋友,他在7 号城市可以购买两种过路券。他可以花3 元买一张可以使用2次的券,然后在3 号城市再买一张2 元,可以使用3
次的券,走到首都。总花费是5 元,而且其他的购买方式不会比这种更省钱。

• 对于40% 的数据:n, m, q <= 10, wi <= 10;
• 另有20% 的数据:n, m, q <= 500, wi <=100;
• 另有20% 的数据:n, m, q <= 5000, wi <= 1000;
• 对于100% 的数据:n, m, q <=10^5, wi <= 10000; 1 <= vi, ki <= n。

记忆化搜索,向他可以到的点搜索,记忆化就可以了。

var
tot,i,n,u,v,l,q,m:longint;
head,ret,next,cost,f,dp:array[0..200022] of longint;
function min(a,b:longint):longint;
begin
  if a<b then exit(a) else exit(b);
end;

procedure ins(u,v,l:longint);
begin
  tot:=tot+1;
  ret[tot]:=v;
  cost[tot]:=l;
  next[tot]:=head[u];
  head[u]:=tot;
end;

function dfs(u:longint):longint;
var
i,k,fa,num:longint;
begin
  if u=1 then exit(0);
  if dp[u]<>-1 then exit(dp[u]);
  dp[u]:=maxlongint;
  i:=head[u];
  while i<>0 do
  begin
    k:=ret[i];
    fa:=f[u];
    num:=1;
    while (fa>=1)and(num<=k) do
    begin
      dp[u]:=min(dp[u],dfs(fa)+cost[i]);
      fa:=f[fa];
      num:=num+1;
    end;
    i:=next[i];
  end;
  exit(dp[u]);
end;

begin
  readln(n,m);
  for i:=1 to n-1 do
  begin
    read(u);
    readln(f[u]);
  end;
  for i:=1 to m do
  begin
    readln(u,v,l);
    ins(u,v,l);
  end;
  readln(q);
  fillchar(dp,sizeof(dp),$ff);
  for i:=1 to q do
  begin
    readln(u);
    writeln(dfs(u));
  end;
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值