HDU 6326 Monster Hunter (贪心)

hdu6326 有一些怪物构成了树形结构,在打第i只怪的时候,会先扣ai点血量,再扣bi点血量。要求在打一只怪之前必须先打它父节点位置上的怪,问要使这个过程中的血量不会降低到0以下,初始的时候最少要有多少点血。

考虑打怪的先后顺序,对于i,j两只怪物,如果先打i,这个过程中的最低血量就是A=min(-ai,-ai+bi-aj),反之如果先打j就是B=min(-aj,-aj+bj-ai)。显然如果A>B就需要先打i,否则就先打j。

但是直接贪心是不正确的,因为有必须先打父节点再打子节点的条件。于是我们就在一开始把所有的点放进优先队列中,每次将选出的节点和它的父节点合并成一个节点,合并的时候同样也遵循贪心的原则。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
#define maxn 100050
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;

int t,n,m,pre[maxn];
bool vis[maxn];
vector<int>maze[maxn];
ll Min(ll a,ll b){return a<b?a:b;}
struct node
{
    ll x,y;
    int id,num;
    bool operator < (const node& o)const
    {
        return Min(x,x+o.x+y) < Min(o.x,o.x+x+o.y);
    }
}e[maxn];
priority_queue<node>q;

int Find(int x)
{
    if(!vis[pre[x]])return pre[x];
    return pre[x]=Find(pre[x]);
}

void init()
{
    for(int i=1;i<=n;i++)
        maze[i].clear(),pre[i]=i;
    memset(vis,0,sizeof(vis));
    //memset(head,-1,sizeof(head));
}

void dfs_pre(int u,int fa)
{
    pre[u]=fa;
    int len=maze[u].size();
    for(int i=0;i<len;i++)
    {
        int v=maze[u][i];
        if(v!=fa)dfs_pre(v,u);
    }
}

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        init();
        e[1].x=e[1].y=0,e[1].id=1,e[1].num=0;
        for(int i=2;i<=n;i++)
        {
            scanf("%lld%lld",&e[i].x,&e[i].y);
            e[i].x*=-1;
            e[i].id=i;
            e[i].num=0;
        }
        int u,v;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            maze[u].push_back(v);
            maze[v].push_back(u);
        }
        dfs_pre(1,1);
        while(!q.empty())q.pop();
        for(int i=2;i<=n;i++)
            q.push(e[i]);
        int cnt=0;
        while(!q.empty())
        {
            node now=q.top();
            q.pop();
            int u=now.id;
            if(vis[u])continue;
            if(now.num!=e[u].num)continue;
            vis[u]=1;
            int fa=Find(u);
            if(e[u].x+e[fa].y<0)
            {
                e[fa].x+=(e[u].x+e[fa].y);
                e[fa].y=e[u].y;
            }
            else e[fa].y+=(e[u].x+e[u].y);
            if(fa>1)
            {
                e[fa].num=++cnt;
                q.push(e[fa]);
            }
        }
        printf("%lld\n",-e[1].x);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/NPU_SXY/article/details/81358834