hdu 6326 Problem H. Monster Hunter(贪心+并查集)

Problem H. Monster Hunter

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 663    Accepted Submission(s): 158


 

Problem Description

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 n−1bidirectional 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.

 

Input

The first line of the input contains an integer T(1≤T≤2000), denoting the number of test cases.
In each test case, there is one integer n(2≤n≤100000) in the first line, denoting the number of intersections.
For the next n−1 lines, each line contains two integers ai,bi(0≤ai,bi≤109), describing monsters at the 2,3,...,n-th intersection.
For the next n−1 lines, each line contains two integers u and v, denoting a bidirectional road between the u-th intersection and the v-th intersection.
It is guaranteed that ∑n≤106.

 

Output

For each test case, print a single line containing an integer, denoting the minimum initial HP.

 

Sample Input

 

1 4 2 6 5 4 6 2 1 2 2 3 3 4

 

Sample Output

 

3

 

Source

2018 Multi-University Training Contest 3

 

Recommend

chendu   |   We have carefully selected several similar problems for you:  6343 6342 6341 6340 6339 

 题意: 用最小的花费干掉所有的怪兽。

思路: 如果不考虑父亲的限制关系,我们可以怎么做呢,如果不考虑父亲的限制关系,这个题就比较简单了,现在把所有的怪兽分为两种,第一种,a<b 表示干掉这个怪兽之后我们的money会变多。那么对于这种怪兽我们就当然是先干掉花费小的怪兽了。那么对于a>=b 的怪兽呢,干掉这些怪兽之后我们的money 会变少,其实可以反过来考虑,要想使得总花费最小,那么我就要尽量浪费的少,如何浪费的少呢,就是把b 小的放后边去打。所以对于这种怪兽,我们要先干掉b大的。

那么贪心贪完了,难点就来了,我们要如何考虑父亲孩纸之间的限制关系呢,对于每个孩纸,如果他的优先级(也就是上边的排序结果)是当前的最高,但是他的父亲优先级比较低,那么我们就可以将他并到父亲节点上,然后更新父亲节点的优先级,塞到堆里边,为什么可以这么做呢,因为如果现在改变了的父亲的优先级是当前最高的,那么我们干掉父亲之后,应该先干哪个呢? 如果有孩纸并在他的身上,那么我们干掉父亲之后,当然要先干掉这个优先级比他的父亲还要高的孩纸了。那么这里还有一个问题,我们把孩纸并到父亲身上,那么父亲的优先级要怎么去改变呢? 自己想想。。。 也就是简单的改变a和b 那么我们不断地去把孩纸并到父亲身上,那么最终就肯定只有一个父亲了,那么父亲的a也就是答案了。 父亲优先级代码在下边。。。

代码:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N =1e5+5;

struct yjt
{
    ll a,b;
    int ind;
    bool operator <(const yjt &x) const
    {
        if(b>a&&x.b>x.a){
            return x.a<a;
        }
        else if(b<=a&&x.b<=x.a){
            return x.b>b;
        }
        else if(b<=a&&x.b>x.a) return true;
		return false;
    }
}cc[N];

priority_queue<yjt> q;
int f[N];
vector<int >ve[N];
int tmpfa[N];
int n;

void init()
{
    for(int i=0;i<=n;i++) f[i]=i;
    while(!q.empty()) q.pop();
    memset(tmpfa,0,sizeof(tmpfa));
    for(int i=0;i<=n;i++) ve[i].clear();
}

void dfs(int u,int fa)
{
    tmpfa[u]=fa;
    for(int i=0;i<ve[u].size();i++){
        int v=ve[u][i];
        if(v==fa) continue;
        dfs(v,u);
    }
}

int getf(int x)
{
    return f[x]==x?x:(f[x]=getf(f[x]));
}

int main()
{
    int T;
    int u,v;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        init();
        cc[1].a=0; cc[1].b=0; cc[1].ind=1;
        for(int i=2;i<=n;i++){
            scanf("%lld %lld",&cc[i].a,&cc[i].b);
            cc[i].ind=i;
        }

        for(int i=2;i<=n;i++){
            scanf("%d %d",&u,&v);
            ve[u].push_back(v);
            ve[v].push_back(u);
        }
        dfs(1,1);

        for(int i=2;i<=n;i++){
            q.push(cc[i]);
            //cout<<cc[i].a<<" "<<cc[i].b<<" "<<cc[i].ind<<endl;
        }

        while(!q.empty()){
            yjt tmp=q.top();
            u=tmp.ind;
            if(u==1|| (cc[u].a!=q.top().a ||cc[u].b!=q.top().b) ){  // 如果现在弹出来的是根节点1
                 //或者是一个已经被修改过的某个父节点
                q.pop();
                continue;
            }
            q.pop();
            int ff=getf(tmpfa[u]);
            //cout<<"fath "<<ff<<endl;
            f[u]=ff;
            yjt &tt=cc[ff];
            tt.a+=max(0ll,cc[u].a-cc[ff].b);
            tt.b=cc[u].b+max(0ll,cc[ff].b-cc[u].a);
            q.push(tt);
        }

        ll ans=cc[1].a;
        cout<<ans<<endl;
    }
    return 0;
}

/*
1
5
3 5
4 6
2 7
10 1
1 2
2 3
2 4
1 5

*/

猜你喜欢

转载自blog.csdn.net/yjt9299/article/details/81390379