题目链接
https://vjudge.net/problem/CodeForces-1436D
题意
n个节点,n-1条单向边,连通图,每一个点有一定的人数,人们从1点开始,沿单向路走动,歹徒从1点开始,沿道路追赶,追到无路可走停止,歹徒知道所有人的位置,整张图的情况,人们也知道歹徒位置,人可以相互配合,问人和歹徒都选择最优策略情况下,歹徒能追到的人数
思路
我们先跑一遍dfs处理每个节点为根的子树的总权值和叶子节点个数。
当最理想情况下,某一根节点的全部人(包含子节点的人)都平均的走向不同的路,最终歹徒追到的人是总权值/叶子节点个数
但因为子节点都提前有一定的人数,且路是单向路,不能回走,所以可能存在某一个子节点人已经非常多,无论怎么分配根节点的人员移动,都无法达到平均的情况。
对于这种情况,歹徒一定会走向那一条无法被平均的路,我们记这个节点为x,那么我们最佳策略是全部走其他的路,不向x分配任何一个人员。那以当前节点为根的数的答案就是递归的求以x节点为根的子树的答案。
因为所有节点最终都会走向叶子节点,叶子节点一定是可以平均分的,那么最终所有情况都会变成最理想情况。
我们再考虑以x为根的情况,最理想情况求取的答案一定是小于等于不能平均的答案的,于是我们可以遍历每一个节点,按照最理想情况求值,最终答案取max即可。
代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<string>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
#define int long long
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=300010;
const int maxe=300010;
int head[maxn],cnt;
struct Edge{
int v;
int w;
int next;
}edge[maxe];
int out[maxn];
int sn[maxn];
ll sm[maxn];
int va[maxn];
int ans=inf;
inline void add(int u,int v,int w=0){
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void init(){
memset(head,-1,sizeof(head));
cnt=0;
return ;
}
void dfs(int x){
// if(x==-1)
// return 1;
int total=0;
int son=0;
bool bl=0;
for(int i=head[x];~i;i=edge[i].next){
dfs(edge[i].v);
bl=1;
son+=sn[edge[i].v];
total+=sm[edge[i].v];
}
sm[x]=total+va[x];
if(!bl)
sn[x]=1;
else
sn[x]=son;
}
signed main(){
IOS
init();
int n;
cin>>n;
for(int i=2;i<=n;i++){
int tmp;
cin>>tmp;
add(tmp,i);
out[tmp]++;
}
for(int i=1;i<=n;i++){
cin>>va[i];
}
dfs(1);
int ans=-inf;
for(int i=1;i<=n;i++){
int t=ceil((double)sm[i]/sn[i]);
ans=max(ans,t);
}
cout<<ans<<endl;
return 0;
}