1. 程式人生 > >HEOI2015 兔子與櫻花

HEOI2015 兔子與櫻花

向上 cst gis head sign break 其中 數據 \n

Time Limit: 10 Sec Memory Limit: 256 MB

Description

很久很久之前,森林裏住著一群兔子。有一天,兔子們突然決定要去看櫻花。兔子們所在森林裏的櫻花樹很特殊。櫻花樹由\(n\)個樹枝分叉點組成,編號從\(0\)\(n-1\),這\(n\)個分叉點由\(n-1\)個樹枝連接,我們可以把它看成一個有根樹結構,其中\(0\)號節點是根節點。這個樹的每個節點上都會有一些櫻花,其中第\(i\)個節點有\(c_i\)朵櫻花。櫻花樹的每一個節點都有最大的載重\(m\),對於每一個節點\(i\),它的兒子節點的個數和i節點上櫻花個數之和不能超過\(m\),即\(son(i) + c_i \leq m\)

,其中\(son(i)\)表示\(i\)的兒子的個數,如果\(i\)為葉子節點,則\(son(i) = 0\)

現在兔子們覺得櫻花樹上節點太多,希望去掉一些節點。當一個節點被去掉之後,這個節點上的櫻花和它的兒子節點都被連到刪掉節點的父節點上。如果父節點也被刪除,那麽就會繼續向上連接,直到第一個沒有被刪除的節點為止。

現在兔子們希望計算在不違背最大載重的情況下,最多能刪除多少節點。

註意根節點不能被刪除,被刪除的節點不被計入載重。

Input

第一行輸入兩個正整數,\(n\)\(m\)分別表示節點個數和最大載重

第二行\(n\)個整數\(c_i\),表示第\(i\)個節點上的櫻花個數

接下來\(n\)

行,每行第一個數\(k_i\)表示這個節點的兒子個數,接下來\(k_i\)個整數表示這個節點兒子的編號

Output

一行一個整數,表示最多能刪除多少節點。

Sample Input

10 4
0 2 2 2 4 1 0 4 1 1
3 6 2 3
1 9
1 8
1 1
0
0
2 7 4
0
1 5
0

Sample Output

4

HINT

對於\(100\%\)的數據,\(1 \leq n \leq 2000000\), \(1 \leq m \leq 100000\), \(0 \leq c_i \leq 1000\)

數據保證初始時,每個節點櫻花數與兒子節點個數之和大於\(0\)且不超過\(m\)

Solution

我們的重量顯然就是櫻花數+子節點數。

我們現在要盡量刪最多的點。

對於一個點\(x\),它的所有子節點內能刪多少點顯然與\(x\)無關。那麽我們現在也就只關心它的每個子節點能不能刪。

於是我們可以搞出來一個新數組\(c[i]\)表示當\(i\)這個點取了最多的點時候的重量。

然後我們現在把所有子節點都按照\(c\)值從小到大排序,優先選擇比較小的點刪除。為什麽是對的呢?可以這樣考慮吧,如果有一個重量比較大的點沒有選,那麽事實上我們只會損失掉那個子節點的1個貢獻。但是,如果我們選了重量比較小的,有可能會使得整個這個子樹的根節點在其父親那裏選不了(這是也只會損失1個貢獻),更有可能會使得在其父親那裏可以選(那麽就很好什麽貢獻都不會損失),因此優先選擇小的肯定不會差。

所以我們現在就是采取優先選擇\(c\)值小的點的策略,一定可以得到最優解。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
#define lowbit(x) ((x)&(-(x)))
#define REP(i,a,n) for(register int i=(a);i<=(n);++i)
#define PER(i,a,n) for(register int i=(a);i>=(n);--i)
#define FEC(i,x) for(register int i=head[x];i;i=g[i].ne)
#define dbg(...) fprintf(stderr,__VA_ARGS__)
namespace io{
    const int SIZE=(1<<21)+1;char ibuf[SIZE],*iS,*iT,obuf[SIZE],*oS=obuf,*oT=oS+SIZE-1,c,qu[55];int f,qr;
    #define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),(iS==iT?EOF:*iS++)):*iS++)
    inline void flush(){fwrite(obuf,1,oS-obuf,stdout);oS=obuf;}
    inline int getc(){return gc();}
    inline void putc(char x){*oS++=x;if(oS==oT)flush();}
    template<class I>inline void read(I &x){for(f=1,c=gc();c<'0'||c>'9';c=gc())if(c=='-')f=-1;for(x=0;c<='9'&&c>='0';c=gc())x=x*10+(c&15);x*=f;}
    template<class I>inline void write(I x){if(!x)putc('0');if(x<0)putc('-'),x=-x;while(x)qu[++qr]=x%10+'0',x/=10;while(qr)putc(qu[qr--]);}
    inline void print(const char *s){while(*s!='\0')putc(*s++);}
    inline void scan(char *s){for(c=gc();c<=' ';c=gc());for(;c>' ';c=gc())*(s++)=c;*s='\0';}
    struct Flusher_{~Flusher_(){flush();}}io_flusher_;
}//orz laofudasuan
using io::read;using io::putc;using io::write;using io::print;
typedef long long ll;typedef unsigned long long ull;
template<typename A,typename B>inline bool SMAX(A&x,const B&y){return x<y?x=y,1:0;}
template<typename A,typename B>inline bool SMIN(A&x,const B&y){return y<x?x=y,1:0;}

const int N=2000000+7;
int n,m,x,y,c[N],ans;
vector<int>g[N];

inline char cmp(const int&x,const int&y){return c[x]<c[y];}
inline void DFS(int x){
    int len=g[x].size(),&cnt=c[x];
    for(register int i=0;i<len;++i)DFS(g[x][i]);
    sort(g[x].begin(),g[x].end(),cmp);
    for(register int i=0;i<len;++i)if(cnt+c[g[x][i]]-1<=m){cnt+=c[g[x][i]]-1;++ans;}else break;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("BZOJ4027.in","r",stdin);freopen("BZOJ4027.out","w",stdout);
#endif
    read(n),read(m);
    for(register int i=1;i<=n;++i)read(c[i]);
    for(register int i=1;i<=n;++i){
        read(x);c[i]+=x;
        for(register int j=1;j<=x;++j)read(y),g[i].push_back(y+1);
    }
    DFS(1);write(ans),putc('\n');
}

HEOI2015 兔子與櫻花