1. 程式人生 > >【CodeM初賽B輪】A 貪心

【CodeM初賽B輪】A 貪心

style 排序 但是 cnblogs const 每次 sof pac max

【CodeM初賽B輪】A

題目大意:給你一棵樹,起初所有點都是白色的,你每次都能選擇一個白點i,將這個點i到根路徑上的所有到i的距離<k[i]的點都染成黑色(根和i也算,已經被染成黑色的點還是黑色)。問最少需要染多少次才能將所有點都變黑。

n<=100000

題解:顯然貪心啊,但是我一開始居然寫了樹剖。。。

因為葉子節點是一定要染的,所以我們可以將所有點按DFS序排序,從後往前染。記錄vis[i],表示之前已經將所有到i的距離<=vis[i]的點染成了黑色;再維護mx[i],表示之前染過的點最多能將到i的距離<=mx[i]的點染成黑色。然後用當前的vis和mx去更新fa就行了。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=100010;
int n,cnt,ans;
int fa[maxn],tag[maxn],k[maxn],p[maxn],head[maxn],nxt[maxn],to[maxn],ml[maxn];
void add(int a,int b)
{
	to[cnt]=b,nxt[cnt]=head[a],head[a]=cnt++;
}
void dfs(int x)
{
	p[++p[0]]=x;
	for(int i=head[x];i!=-1;i=nxt[i])	dfs(to[i]);
}
int main()
{
	scanf("%d",&n);
	int i,a;
	memset(head,-1,sizeof(head));
	for(i=2;i<=n;i++)	scanf("%d",&fa[i]),add(fa[i],i);
	for(i=1;i<=n;i++)	scanf("%d",&k[i]);
	dfs(1);
	for(i=n;i>=1;i--)
	{
		a=p[i];
		ml[a]=max(ml[a],k[a]);
		if(!tag[a])	tag[a]=ml[a],ans++;
		ml[fa[a]]=max(ml[fa[a]],ml[a]-1),tag[fa[a]]=max(tag[fa[a]],tag[a]-1);
	}
	printf("%d",ans);
	return 0;
}

【CodeM初賽B輪】A 貪心