BZOJ 4027: [HEOI2015]兔子与樱花

Description

很久很久之前,森林里住着一群兔子。有一天,兔子们突然决定要去看樱花。兔子们所在森林里的樱花树很特殊。樱花树由n个树枝分叉点组成,编号从 0 n1 ,这 n 个分叉点由 n1 个树枝连接,我们可以把它看成一个有根树结构,其中 0 号节点是根节点。这个树的每个节点上都会有一些樱花,其中第 i 个节点有 ci 朵樱花。樱花树的每一个节点都有最大的载重 m ,对于每一个节点 i ,它的儿子节点的个数和i节点上樱花个数之和不能超过 m ,即 son(i)+ci<=m ,其中 son(i) 表示i的儿子的个数,如果 i 为叶子节点,则 son(i)=0

现在兔子们觉得樱花树上节点太多,希望去掉一些节点。当一个节点被去掉之后,这个节点上的樱花和它的儿子节点都被连到删掉节点的父节点上。如果父节点也被删除,那么就会继续向上连接,直到第一个没有被删除的节点为止。
现在兔子们希望计算在不违背最大载重的情况下,最多能删除多少节点。
注意根节点不能被删除,被删除的节点不被计入载重。

Solution

诶竟然1A了,不可思议。
这个贪心感觉很奇怪。。
首先如果 v 和它的一个子节点 t 合并了,那么这个节点的载重变成了 c[v]+c[t]+son[v]son[t]1 ,那么我们按照 c[t]son[t] 排序来更新点即可咯。
还有一件事就是如果点 A 可以删 B ,点 B 可以删 C ,但 B 删了 C 就不可以和 A 并了,该怎么决策?
反正都是缩一个,观察,若缩下面,就这样,但缩上面,可能干扰其它点缩,并且下面的也不可能再缩上去,亏了,所以缩下面即可。

那么就是一遍dfs可以搞定的事情了。

Code

/**************************************************************
    Problem: 4027
    User: bblss123
    Language: C++
    Result: Accepted
    Time:4696 ms
    Memory:61080 kb
****************************************************************/

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define pb push_back
#define ph push
#define vecn vector
#define pqn priority_queue
#define debug cout<<#x<<" "<
#define frt fisrt
#define snd second
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vec;
typedef priority_queue<int> pq;
const int INF=1<<30;
const ll inf=1ll<<60;
const int M=2e6+5;
inline void Max(int &a,int b){if(avoid Min(int &a,int b){if(a>b||a==-1)a=b;}
inline void rd(int &a){
    a=0;char c;
    while(c=getchar(),!isdigit(c));
    do a=a*10+(c^48);
        while(c=getchar(),isdigit(c));
}
inline void work(ll x){
    if(!x)return;
    work(x/10);
    putchar(48+x%10);
}
inline void print(ll x){
    if(!x)putchar('0');
    else work(x);
}
int n,m,c[M],son[M],ans;
vec G[M];
struct node{
    int val,x;
    inline bool operator < (const node &tmp)const{
        return val>tmp.val;
    }
};
inline void dfs(int v){
    pqn que;for(;!que.empty();)que.pop();
    for(int i=0;iint to=G[v][i];
        dfs(to);
        que.push((node){c[to]+son[to],to});
    }
    for(;!que.empty();){
        node u=que.top();que.pop();
        if(c[v]+son[v]+u.val-1<=m){
            c[v]+=c[u.x],son[v]+=son[u.x]-1;
            ++ans;
        }
        else break;
    }
}
//////////////////////////////////////////////////////////////////////////////////////////////
//#define LOCAL
//////////////////////////////////////////////////////////////////////////////////////////////
int main(){
#ifdef LOCAL
    freopen("data.in","r",stdin);
    freopen("data.out","w",stdout);
#endif
    cin>>n>>m;
    for(int i=0;ifor(int i=0;ifor(int j=1,a;j<=son[i];++j)
            rd(a),G[i].pb(a);
    }
    dfs(0);
    cout<return 0;
}

你可能感兴趣的:(常用解题技巧,-----贪心,BZOJ)