1. 程式人生 > >hdu 6326 Problem H. Monster Hunter(貪心+並查集)

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

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

*/