思路:记录每个点的梅花数w、最左儿子ls、最右儿子rs、编号n、父节点f、子节点的最大放置费用mw、子节点维护费用fw,从叶子节点开始搜,一个节点的子节点全搜完后把它当作叶子继续搜,最后到根(类似拓扑排序),感觉是没问题的,样例全过,交测评只能过一个。
#include <iostream>
#include <cstdio>
#include <queue>
#define fo(i,x,y,k) for(register int i = x; k*i < k*y; i+=k)
using namespace std;
const int maxn=1e5+4;
long long ans[maxn];
int n;
struct po{
int f=0,ls=0x3f3f3f,rs=-1,n,w,cnt=0;
long long mw=0,fw=0;
}p[maxn];
queue<po> ps;
int fr() {
int x=0;char c=getchar();
while(c<'0'||c>'9'){
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<3)+(x<<1)+(c^48);
c=getchar();
}
return x;
}
inline long long _max(long long x,long long y) {
return (x>y) ? x : y;
}
inline void upd(int x) {
int f = p[x].f;
ans[f]+=p[x].w;
p[f].cnt++;
if(p[f].cnt==p[f].rs-p[f].ls+1||f==0) {
p[f].mw=_max(p[f].mw,ans[x]);
ans[f]+=p[f].w;
ans[f]=_max(ans[f],p[f].mw)+p[f].fw;
if(f) ps.push(p[f]);
}
else {
ans[f]-=p[x].w;
p[f].mw=_max(p[f].mw,ans[x]);
p[f].fw+=p[x].w;
}
return;
}
int main() {
n=fr();
int x;
fo(i,1,n,1) {
x=fr();
p[i+1].f=x;
if(p[x].ls>i+1) p[x].ls=i+1;
if(p[x].rs<i+1) p[x].rs=i+1;
}
fo(i,1,n+1,1) {
x=fr();
p[i].w=x;
p[i].n=i;
if(p[i].rs==-1&&p[i].ls==0x3f3f3f) {
ans[i]=x;
ps.push(p[i]);
}
}
po p1;
while(!ps.empty()){
p1=ps.front();
ps.pop();
upd(p1.n);
}
fo(i,1,n+1,1) {
printf("%lld ",ans[i]);
}
return 0;
}