HEOI2015 兔子與櫻花
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\)
現在兔子們覺得櫻花樹上節點太多,希望去掉一些節點。當一個節點被去掉之後,這個節點上的櫻花和它的兒子節點都被連到刪掉節點的父節點上。如果父節點也被刪除,那麽就會繼續向上連接,直到第一個沒有被刪除的節點為止。
現在兔子們希望計算在不違背最大載重的情況下,最多能刪除多少節點。
註意根節點不能被刪除,被刪除的節點不被計入載重。
Input
第一行輸入兩個正整數,\(n\)和\(m\)分別表示節點個數和最大載重
第二行\(n\)個整數\(c_i\),表示第\(i\)個節點上的櫻花個數
接下來\(n\)
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 兔子與櫻花