HDU暑假多校第三场H.Monster Hunter

一、题意

  给定一个树状地图,每个树节点上有一只怪物,打死一只怪物的过程中将会消耗A点HP,打死之后将会获得B点HP。因为树状结构,所以每只怪物必须先打死父节点的怪兽之后在打死子节点的怪物。现在,给定每只怪兽的a,b和树状结构的联通关系,求初始HP最小的击败顺序。

  Little Q is fighting against scary monsters in the game ``Monster Hunter''. The battlefield consists of n intersections, labeled by 1,2,...,n, connected by n1bidirectional roads. Little Q is now at the 1-th intersection, with X units of health point(HP).
There is a monster at each intersection except 1. When Little Q moves to the k-th intersection, he must battle with the monster at the k-th intersection. During the battle, he will lose ai units of HP. And when he finally beats the monster, he will be awarded bi units of HP. Note that when HP becomes negative(<0), the game will over, so never let this happen. There is no need to have a battle at the same intersection twice because monsters do not have extra life.
When all monsters are cleared, Little Q will win the game. Please write a program to compute the minimum initial HP that can lead to victory.

 

二、解题思路

  首先考虑在一般情况下<仅仅给出每只怪物的A,B的情况下>如何进行选择。于是有:

    1. 如果两只怪物的b都大于a,则优先打击a更小的那个怪物。
    2. 如果一只怪物a<b,另一只a>b则优先打击a<b的。
    3. 如果两只怪物的b都小于a,于是有,最小血量的击败方案为min(max(ai,ai+aj-bi),max(aj,aj+ai-bj)),题解提到上述计算式实际上等于比较bi和bj

  之后考虑,加入树边的情况。

  考虑使用优先队列维护最优解,则

    当某一个元素p为上述比较方案的最优解时,

    且p的树根如果被选择后,选择p一定是最优解。

  因此可以将p并入树根节点,后使p得所有子节点成为p的兄弟节点。——因为当p的父节点被选择后,p也已经默认被立刻选择了。

  最终,当所有节点都是根节点的子节点时,计算并比较最优解的具体状态。

 

  考虑一个细节:如何合并两个节点?
    设ai,aj,bi,bj为两个节点的相关变量则有:

    ak = min(max(ai,ai+aj-ai),max(aj,aj+ai-bj))

    bk = ak + bi + bj - ai - aj

#include<bits/stdc++.h>
using namespace std;

#define ll long long
const ll MAXN=100233;
#define veci vector<int>


int fa[MAXN];
int cha[MAXN];

class Node
{
    public:
        ll a,b,num,ver;
        Node(){}
        Node(const Node &n)
        {
            this->a = n.a;
            this->b = n.b;
            this->num = n.num;
            this->ver = n.ver;
        }
        bool operator < (Node const n)const{
            ll tmpa = this->b - this->a;
            ll tmpb = n.b - n.a;
            if(tmpa >= 0 && tmpb >=0)return this->a > n.a;
            if(tmpa >=0 && tmpb < 0)return false;
            if(tmpa < 0 && tmpb >=0)return true;
            if(tmpa < 0 && tmpb < 0)return this->b < n.b;
        }
};
Node nodes[MAXN];
int n;
veci G[MAXN];

void dfs(int now,int father)
{
    fa[now] = father;
    int len = G[now].size();
    for(int i=0;i<len;++i)
    {
        int tar = G[now][i];
        if(tar == father)continue;
        dfs(tar,now);
    }
}

int find_set(int tar)
{
    if(cha[tar] == tar)return tar;
    else return cha[tar] = find_set(cha[tar]);
}

void init()
{
    cin>>n;
    for(int i=0;i<n+23;++i)
    {
        G[i].clear();
        cha[i] = i;
    }    
    priority_queue<Node> pq;
    for(int i=2;i<=n;++i)
    {
        cin>>nodes[i].a>>nodes[i].b;
        nodes[i].num = i;
        nodes[i].ver = 1;
        pq.push(nodes[i]);
    }   
    for(int i=1;i<n;++i)
    {
        int a,b;
        cin>>a>>b;
        G[a].push_back(b);
        G[b].push_back(a);
    }dfs(1,1);

    ll ans = 0;
    ll money = 0;

    while(!pq.empty())
    {
        Node node = pq.top();
        pq.pop();

        int now = node.num;
        if(node.ver != nodes[now].ver)continue;
        int father = fa[now];
        father = find_set(father);
        nodes[now].ver = -1;
        cha[now] = cha[father];
        if(father == 1)
        {
            if(node.a > money)
            {
                ans += node.a-money;
                money = node.b;
            }else{
                money -= node.a;
                money += node.b;
            }
            continue;
        }

        nodes[father].ver ++;
        ll tmp = nodes[father].b +node.b - nodes[father].a-node.a;
        nodes[father].a = max(nodes[father].a, nodes[father].a + node.a - nodes[father].b);
        nodes[father].b = nodes[father].a + tmp;
        Node newNode(nodes[father]);
        pq.push(newNode);
    }

    cout<<ans<<"\n";
}

int main()
{
    cin.sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--)init();

    return 0;
}

 

posted @ 2018-08-03 01:29  六花的邪王真眼  阅读(426)  评论(0编辑  收藏  举报