[bzoj4027][HEOI2015]兔子与樱花_贪心_树形dp

兔子与樱花 bzoj-4027 HEOI-2015

题目大意:每个点有c[i]朵樱花,有一个称重m, son[i]+c[i]<=m.如果删除一个节点,这个节点的樱花或移动到它的祖先中深度最大的,且没有被删除的节点,求在满足所有点界限的情况下,最多能删除的节点数。

注释:$1\le n\le 2\cdot 10^6$,$1\le m\le 10^5$,$0\le c_i\le 1000$。

想法:开始的时候很容易想到贪心,但是这东西对不对还两说

其实仔细一想这玩意儿tm显然啊??!

我们令c[i]+son[i]为这个点的优先级,我们显然选优先级高的。

如果我们选了一个优先级略低的,比如说是最高优先级的..子孙?这样的话我只会是的上面的优先级哐哐往上涨直到不合法

祖先的话删完了之后优先级高的迟早要删,这样的话底下的樱花上来就GG了。

最后,附上丑陋的代码... ...

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int maxn=2000010,maxm=maxn<<1;
using namespace std;
int n,m,pre[maxm],now[maxn],son[maxm],tot,c[maxn],a[maxn],ans;
bool ok;char ch;
void read(int &x){
	for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1;
	for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
	if (ok) x=-x;
}
void add(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;}
void dfs(int x){
	for (int y=now[x];y;y=pre[y]) dfs(son[y]);
	int cnt=0;
	for (int y=now[x];y;y=pre[y]) a[++cnt]=c[son[y]];
	sort(a+1,a+1+cnt);
	for (int i=1;i<=cnt;i++){
		if (c[x]+a[i]-1>m) break;
		c[x]+=(a[i]-1),ans++;
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++) read(c[i]);
	for (int i=1,x,num;i<=n;i++){
		read(num),c[i]+=num;
		for (int j=1;j<=num;j++) read(x),x++,add(i,x);
	}
	dfs(1),printf("%d\n",ans);
	//for (int i=1;i<=n;i++) printf("%d %d %d\n",i,f[i],g[i]);
	return 0;
}

小结:对于这种贪心的题,我们还是需要证明一下的... ...

posted @ 2018-07-07 19:08  JZYshuraK_彧  阅读(162)  评论(0编辑  收藏  举报