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