[贪心+并查集+堆]HDU6326(2018多校训练赛第三场 Problem H)Monster Hunter 题解

版权声明:本文为博主原创文章,欢迎转载。 https://blog.csdn.net/try__jhf/article/details/82108132

一种好像之前做过这道题的感觉,然后发现……没用。

题目大意

你现在正在打一个游戏”Monster Hunter“,游戏中你在一个有 n 个节点的地图上,一共有 n 1 条双向边相连,初始时你在节点1上,初始HP值为 X ,节点2,3,…,n各有一个怪兽,要消灭第 i 个怪兽需要 a i 点HP,在消灭第 i 个怪兽之后又可以得到 b i 的HP,消灭第 i 个怪兽需要先把他和你之间所有怪兽全部消灭。求消灭所有怪兽所需要的最小初始HP值 X

解题报告

看了官方Blog 10min后自己动手敲,然后发现难以实现……


官方Blog的题解还是很好懂的,以1为根建有根树,如果消灭第 i 个怪兽就需要把他父节点怪兽消灭掉,所以有父节点限制,所以先考虑把这个限制取消,即给出 n 1 个怪兽,求消灭他们所需的最小HP值。

不妨把所有怪兽分成两类: a < b a b ,前者打完加血,后者扣血,然后发现先打前者明显更划算。

分类讨论:

a < b : 明显把a从小到大打更优。

a b :这里可以使用贪心常用的推论方法,设两个变量 i , j ,若 i j 更优,则

H P m a x ( a i , a i b i + a j ) > H P m a x ( a j , a j b j + a i )

m a x ( a j , a j b j + a i ) m a x ( a i , a i b i + a j ) > 0

再分三类:

1. a i < b j a j < b i ,则如果 a i > b i ,能推出 a j < b j ,与前提不符,反之亦然,故舍去。

2. a i < b j a j > b i a i > b j a j < b i

假设 a i < b j a j > b i ,则 b i a i < b j a j

此时 a j ( a i b i + a j ) > 0

b i a i > 0 b i > a i ,与前提不符,故舍去。

3. a i > b j a j > b i ,则

a j b j + a i a i + b i a j > 0

b i b j > 0

(原来Blog就这几句不明所云的话,所以这里我写了比较长的证明,比较蠢,看看就好)

综上,若 a b ,按照 b 从大到小消灭。


所以以上,我们已经得出了在没有父节点限制下的处理顺序 p 1 , p 2 , p 3 , . . , p n

然后带回原题,如果有父节点限制,该怎么办?

又分类:

1.如果 f a t h e r [ p 1 ] = 1 ,即 p 1 没有父亲限制,那么第一步打 p 1 一定最优。

2.如果 f a t h e r [ p 1 ] 1 ,即 p 1 有父亲限制,那么在处理完 p 1 的父亲后紧接着处理 p 1 一定最优,所以可以将 p 1 和他的父亲合并,计算出新的 ( a , b ) (如何计算见代码+=),并将 p 1 所有儿子节点的父亲设为 p 1 的父亲。

这样的话 p 1 的问题就解决了,将规模为 n 的问题化成了规模为 n 1 的问题,然后重复操作直到只剩下一只怪兽即可求出最少所需血量。

然后求最优策略带插入,堆

求父亲待修改,并查集

然后……好了?

示例代码

题目传送门

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 100005
#define maxe 200005
using namespace std;
typedef long long LL;
int n,len,tot,tst,lnk[maxn],son[maxe],nxt[maxe],fa[maxn],father[maxn],num[maxn];
struct data{
    LL x,y; int id,s;
    data (LL x=0,LL y=0,int id=0,int s=0):x(x),y(y),id(id),s(s){}
    bool operator < (const data b)const{
        if (x<y&&b.x>=b.y) return 1;
        if (x>=y&&b.x<b.y) return 0;
        if (x<y&&b.x<b.y) return x<b.x||(x==b.x&&y>b.y);
        if (x>=y&&b.x>=b.y) return y>b.y||(y==b.y&&x<b.x);
    }
    data operator += (const data t){
        LL a=max(x,x-y+t.x),b=y-x+t.y-t.x+a;
        x=a; y=b; return *this;
    } //将该节点的怪兽与父节点合并
}a[maxn];
struct hep{
    data hep[maxn];
    void put(data a){
        hep[++len]=a;
        for (int son=len;son!=1&&hep[son]<hep[son>>1];son>>=1) swap(hep[son],hep[son>>1]);
    }
    data get(){
        data ans=hep[1]; hep[1]=hep[len--];
        for (int fa=1,son;(fa<<1)<=len;fa=son){
            son=fa<<1;
            if (son<len&&hep[son+1]<hep[son]) son++;
            if (hep[son]<hep[fa]) swap(hep[son],hep[fa]); else break;
        }
        return ans;
    }
}h; //手写堆……
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void readi(int &x){
    x=0; char ch=nc();
    while ('0'>ch||ch>'9') ch=nc();
    while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=nc();}
}
void _add(int x,int y){
    son[++tot]=y; nxt[tot]=lnk[x]; lnk[x]=tot;
}
void _dfs(int x,int dad){
    for (int j=lnk[x];j;j=nxt[j])
        if (son[j]!=dad){father[son[j]]=x; _dfs(son[j],x);}
}
void _init(){
    readi(n); tot=len=0; a[1]=data(0,0,1,0);
    for (int i=1,j=1;i<=n;i++,j+=2) lnk[i]=son[j]=son[j+1]=nxt[j]=nxt[j+1]=0;
    for (int i=2,x,y;i<=n;i++) {readi(x); readi(y); a[i]=data(x,y,i,0); h.put(a[i]);}
    for (int i=1,x,y;i<n;i++) {readi(x); readi(y); _add(x,y); _add(y,x);}
}
int f_get(int x){return fa[x]==x?fa[x]:fa[x]=f_get(fa[x]);}
void _solve(){
    _dfs(1,0); int p=0;
    for (int i=1;i<=n;i++) {fa[i]=i; num[i]=0;}
    while (len){
        data b=h.get(); int x=b.id;
        if (b.s!=num[x]) continue;  //num[x]是更新次数,以防在堆中选重
        int dad=f_get(father[x]); a[dad]+=a[x]; fa[x]=dad;
        if (dad>1){
            a[dad].s=num[dad]=++p; h.put(a[dad]);
        }
    }
    printf("%lld\n",a[1].x);
}
int main()
{
    freopen("hunter.in","r",stdin);
    freopen("hunter.out","w",stdout);
    readi(tst);
    while (tst--){
        _init();
        _solve();
    }
    return 0;
}

一个优先级刚了我1d的题目……

猜你喜欢

转载自blog.csdn.net/try__jhf/article/details/82108132