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

[bzoj3875] [Ahoi2014]騎士遊戲

push family urn ahoi2014 max struct while har getchar()

3875: [Ahoi2014]騎士遊戲

Time Limit: 30 Sec Memory Limit: 256 MB
Submit: 844 Solved: 440
[Submit][Status][Discuss]

Description

【故事背景】 長期的宅男生活中,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

題解

  第一眼看到貌似是個dp,假如f[i]是殺死i所需要的代價,那麽f[i]=max{k[i],s[i]+∑f[j](i為j的父親)}。但是一個怪獸的分裂出的怪獸也有可能分裂出他自己來,不滿足無後向性。我們可以用spfa來解決這個問題,一開始把所有怪獸加入隊列,一旦隊首的兒子可以對他進行更新,那麽將他的所有父親加入隊列(這時他可以更新他的父親)。

註意事項

 數據範圍需要開long long。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
#define REP(i,a,b) for(register int i=(a),_end_=(b);i<=_end_;i++)
#define DREP(i,a,b) for(register int i=(a),_end_=(b);i>=_end_;i--)
#define EREP(i,a) for(register int i=start[(a)];i;i=e[i].next)
inline int read()
{
    int sum=0,p=1;char ch=getchar();
    while(!((0<=ch && ch<=9) || ch==-))ch=getchar();
    if(ch==-)p=-1,ch=getchar();
    while(0<=ch && ch<=9)sum=sum*10+ch-48,ch=getchar();
    return sum*p;
}

const int maxn=2e5+20;

int n;
ll s[maxn],k[maxn];
ll f[maxn];

struct node {
    int v,next;
};
node e[maxn*10];
int start[maxn],cnt=0;

inline void addedge(int u,int v)
{
    e[++cnt]={v,start[u]};
    start[u]=cnt;
}

inline void init()
{
    n=read();
    REP(i,1,n)
    {
        //s[i]=read(),k[i]=read();
        cin>>s[i]>>k[i];
        register int x=read();
        REP(j,1,x)
        {
            int v=read();
            addedge(i,v);
            addedge(v,i);
        }
    }
}

int vis[maxn];
#include<queue>
inline void doing()
{
    queue<int>q;
    REP(i,1,n)f[i]=k[i],vis[i]=1;
    REP(i,1,n)q.push(i);
    do{
        register int u=q.front();
        register ll sum=s[u];q.pop();
        EREP(i,u)
        {
            if(!(i & 1))continue;
            register int v=e[i].v;
            sum+=f[v];
        }
        if(sum<f[u])
        {
            f[u]=sum;
            EREP(i,u)
            {
                if(i & 1)continue;
                register int v=e[i].v;
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
        vis[u]=0;
    }while(!q.empty());
    cout<<f[1]<<endl;
}

int main()
{
    init();
    doing();
    return 0;
}

  

[bzoj3875] [Ahoi2014]騎士遊戲