1. 程式人生 > >[AHOI2014]騎士遊戲

[AHOI2014]騎士遊戲

【故事背景】
長期的宅男生活中,JYY又挖掘出了一款RPG遊戲。在這個遊戲中JYY會
扮演一個英勇的騎士,用他手中的長劍去殺死入侵村莊的怪獸。
【問題描述】
在這個遊戲中,JYY一共有兩種攻擊方式,一種是普通攻擊,一種是法術攻
擊。兩種攻擊方式都會消耗JYY一些體力。採用普通攻擊進攻怪獸並不能把怪獸徹底殺死,怪獸的屍體可以變出其他一些新的怪獸,注意一個怪獸可能經過若干次普通攻擊後變回一個或更多同樣的怪獸;而採用法術攻擊則可以徹底將一個怪獸殺死。當然了,一般來說,相比普通攻擊,法術攻擊會消耗更多的體力值(但由於遊戲系統bug,並不保證這一點)。
遊戲世界中一共有N種不同的怪獸,分別由1到N編號,現在1號怪獸入
侵村莊了,JYY想知道,最少花費多少體力值才能將所有村莊中的怪獸全部殺死呢?
Input

第一行包含一個整數N。
接下來N行,每行描述一個怪獸的資訊;
其中第i行包含若干個整數,前三個整數為Si,Ki和Ri,表示對於i號怪獸,
普通攻擊需要消耗Si的體力,法術攻擊需要消耗Ki的體力,同時i號怪獸死亡後會產生Ri個新的怪獸。表示一個新出現的怪獸編號。同一編號的怪獸可以出現多個。
Output

輸出一行一個整數,表示最少需要的體力值。

Sample Input

4

4 27 3 2 3 2

3 5 1 2

1 13 2 4 2

5 6 1 2
Sample Output

26
HINT

【樣例說明】

首先用消耗4點體力用普通攻擊,然後出現的怪獸編號是2,2和3。花費

10點體力用法術攻擊殺死兩個編號為2的怪獸。剩下3號怪獸花費1點體力進

行普通攻擊。此時村莊裡的怪獸編號是2和4。最後花費11點體力用法術攻擊

將這兩隻怪獸徹底殺死。一共花費的體力是4+5+5+1+5+6=26。

【資料範圍】

2<=N<=2*10^5,1<=Ri,Sigma(Ri)<=10^6,1<=Ki,Si<=5*10^14

分析:要殺死一個怪物,要麼直接法術攻擊,要麼普通攻擊到某一位置在用法術攻擊殺死新產生的怪獸。
cost[i]=min(k[i],s[i]+∑cost[son[i]])
這是一個環,但這個環到某一個地方必定會斷掉(選擇k[i])
類似spfa,但佇列中存的是待更新的點,一開始dis[i]都賦值為k[i],所以計算一個點,如果它更新了就可能更新它的“父親”,把它的父親入隊。

program bzoj3875;
var t,l,i,n,p,top,tail,u,ss1,j,l1:longint;
    head1,r,head:array[1..200010]of longint;
    b:array[1..3000010]of longint;
    flag:array[1..200010]of boolean;
    edge,edge1:array[1..2000010,1..2]of longint;
    cost,s,k,ss:array[1..200010]of int64;
procedure add(x,y:longint);
begin
 l:=l+1;
 edge[l,1]:=x;
 edge[l,2]:=head[y];
 head[y]:=l;
end;
procedure add1(x,y:longint);
begin
 l1:=l1+1;
 edge1[l1,1]:=y;
 edge1[l1,2]:=head1[x];
 head1[x]:=l1;
end;
begin
 read(n);
 for i:=1 to n do
  begin
  head[i]:=-1;
  head1[i]:=-1;
  end;
 for i:=1 to n do
  begin
   read(s[i],k[i],r[i]);
   ss[i]:=s[i];
   for j:=1 to r[i] do
    begin
     read(t);
     add(i,t);
     add1(i,t);
    end;
  end;
 for i:=1 to n do
  begin
   p:=head1[i];
   while p<>-1 do
    begin
     ss[i]:=ss[i]+k[edge1[p,1]];
     p:=edge1[p,2];
    end;
  end;
 for i:=1 to n do cost[i]:=k[i];
 fillchar(flag,sizeof(flag),false);
 top:=1;tail:=n;
 for i:=1 to n do b[i]:=i;
 repeat
  if ss[b[top]]<cost[b[top]] then
   begin
    p:=head[b[top]];
    while p<>-1 do
     begin
      u:=edge[p,1];
      ss[u]:=ss[u]-cost[b[top]]+ss[b[top]];
      if flag[u] then
       begin
        tail:=tail+1;
        b[tail]:=u;
        flag[u]:=false;
       end;
      p:=edge[p,2];
     end;
    cost[b[top]]:=ss[b[top]];
   end;
  flag[b[top]]:=true;
  top:=top+1;
 until top>tail;
 writeln(cost[1]);
end.