首页 > 技术文章 > CF1436D Bandit in a City 题解

-Iris- 2020-11-04 21:50 原文

思路

一道CF题
看题目很明显可以使用二分,但又想不到很好的judging函数
所以考虑动态规划
先考虑假如完全理想均分
那么每个叶子节点可以被分到\(\lceil\frac{size[u]}{leaf[u]}\rceil\)
(为什么是上取整\(?\)仔细想想
那么现在我们能进行分配的只有当前节点权值
如果每个子节点都小于\(\lceil\frac{size[u]}{leaf[u]}\rceil\)
那么就意味着我们可以对每个点稍微加上那么点权值,使得它们都达到\(\lceil\frac{size[u]}{leaf[u]}\rceil\)左右
那么若存在最大点大于\(\lceil\frac{size[u]}{leaf[u]}\rceil\),我们肯定不会再向这个点加权,
再加权只会让答案变得更劣,所以要尽量"浪费"掉手中的权值,

动态规划方程

\(mxn[x]以x为子树中最大的叶子节点,size[x]x子树中的权值和,leaf[x]x子树中的叶节点个数\)

\[mxn[x] = \max({mxn[y] , \lceil\frac{size[u]}{leaf[u]}\rceil }) \]

Code

#include<iostream>
#include<cstdio>
#include<cmath>

using namespace std;

#define int long long 

const int p=2e5+5;

template<typename _T>
inline void read(_T &x)
{
	x=0;char s=getchar();int f=1;
	while(s<'0'||'9'<s){f=1;if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
	x*=f;
}

int head[p],nxt[p*2],ver[p*2];
int point[p];
int tit;

int leaf[p],mxn[p],size[p];

inline void add(int x,int y)
{
	ver[++tit] = y;
	nxt[tit] = head[x];
	head[x] = tit;
}

inline void dfs(int now,int fa)
{
	size[now] = point[now];
	int cnt=0;
	
	for(int v,i=head[now];i;i=nxt[i])
	{
		if(ver[i] == fa) continue;
		v=ver[i];
		dfs(v,now);
		size[now] += size[v];
		leaf[now] += leaf[v];
		mxn[now] = max(mxn[now] , mxn[v]);
		cnt++;
	}
	
	if(cnt == 0) mxn[now] = point[now],leaf[now]=1;
	
}

inline void bfs(int now,int fa)
{
	for(int i=head[now];i;i=nxt[i])
	{
		int v=ver[i];
		if(v == fa) continue;
		bfs(v,now);
		mxn[now] = max(mxn[now] , max(mxn[v] , (int)ceil((double)size[now]/leaf[now])));
	}
}

signed main()
{
	
	int n;
	
	read(n);
	
	for(int i=2,pi;i<=n;i++)
	{
		read(pi);
		
		add(i,pi);
		add(pi,i);
	}
	
	for(int i=1;i<=n;i++) read(point[i]);
	
	dfs(1,0);
	
	bfs(1,0);
	
	cout<<mxn[1];
	
}

推荐阅读