CodeForces

https://codeforces.com/problemset/problem/1436/D

这题就是让村名尽可能集中在叶子上,但是可能叶子上本来就有很多村民,就是这样。

假设

1.    mx[x]为在x点可以抓到的最多的人

2.    chal[x]为  在x点还差chal[x]人就可以让x下面所有叶子都有x个人

大致就是树形dp的写法了

具体看代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int maxn = 3e5+11;
typedef long long ll;
vector<int>G[maxn];


ll list[maxn];
ll mx[maxn];//最大值 
ll chal[maxn];//缺几个补上 
ll ans[maxn];
ll cns[maxn];


void add(int x,int y){
	G[x].push_back(y);
}

int dfs(int x,int fa){
	ll siz = 0 ;
	for(int i=0;i<G[x].size();i++){
		int p = G[x][i];
		if(p == fa) continue;
		dfs(p,x);
		cns[x] += cns[p];
		siz++;
		
		mx[x] = max(mx[x],mx[p]);//最大值
		chal[x] += chal[p];           
	}
	if(siz == 0){
		
		mx[x] = list[x]; 
		cns[x] = 1;
		return 0;
	}
	siz = cns[x];
	
	for(int i=0;i<G[x].size();i++){
		int  p = G[x][i];
		if(p == fa) continue;
		chal[x] += (mx[x] - mx[p])*cns[p];
	}
	
	if(list[x] > chal[x]){
		list[x] -= chal[x];
		chal[x] = 0;
		mx[x] += list[x] / siz;
		if(list[x] % siz != 0){
			mx[x] ++;
			chal[x] = siz - list[x] % siz;
		}
		list[x] = 0;
	}
	else{
		chal[x] -= list[x];
		list[x] = 0;
	}
	return 0;
}

int main(){
	int n;
	cin>>n;
	int x,y;
	for(int i=2;i<=n;i++){
		cin>>x;
		add(x,i);
		add(i,x);
	}
	for(int i=1;i<=n;i++){
		cin>>list[i];
	}
	dfs(1,-1);
	cout<<mx[1]<<endl;
	
	return 0;
} 

  

原文地址:https://www.cnblogs.com/lesning/p/13886597.html