樹形結構+貪心思維 黑白樹

題目描述:

一棵n個點的有根樹,1號點爲根,相鄰的兩個節點之間的距離爲1。樹上每個節點i對應一個值k[i]。每個點都有一個顏色,初始的時候所有點都是白色的。
你需要通過一系列操作使得最終每個點變成黑色。每次操作需要選擇一個節點i,i必須是白色的,然後i到根的鏈上(包括節點i與根)所有與節點i距離小於k[i]的點都會變黑,已經是黑的點保持爲黑。問最少使用幾次操作能把整棵樹變黑。

輸入描述:

第一行一個整數n (1 ≤ n ≤ 10^5)
接下來n-1行,每行一個整數,依次爲2號點到n號點父親的編號。
最後一行n個整數爲k[i] (1 ≤ k[i] ≤ 10^5)

輸出描述:

一個數表示最少操作次數


在這裏插入圖片描述
配合圖片更好理解

因爲第6個點必須塗色,所以塗了第6個點,第5.4個點也塗了,這個時候如果又從第3個點開始塗,明顯是不優的,直接再塗第5個點就可以了;

所以只要維護每個結點子樹的最大k值,還有每個結點可以往上塗的個數 f ,當f=0時,說明不能往上塗了,這時 f 直接更新爲當前結點的 k 值;

代碼:

#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=100100;
const int M=50100;
const LL mod=1e9+7;
int n,head[N],cnt;
int k[N],f[N],ans;
struct Node{
	int to,nex;
}edge[N*2];
void add(int p,int q){
	edge[cnt].to=q,edge[cnt].nex=head[p],head[p]=cnt++;
}
void dfs(int p,int ft){
	for(int i=head[p];~i;i=edge[i].nex){
		int q=edge[i].to;
		if(q!=ft){
			dfs(q,p);
			f[p]=max(f[p],f[q]-1);
			k[p]=max(k[p],k[q]-1);
		}
	}
	if(f[p]==0){
		ans++;
		f[p]=k[p];
	}
}
int main(){
	memset(head,-1,sizeof(head));
	cin>>n;
	for(int i=2;i<=n;i++){
		int p;cin>>p;
		add(i,p),add(p,i);
	}
	for(int i=1;i<=n;i++) cin>>k[i];
	dfs(1,0);
	cout<<ans<<endl;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章