题意
做法
下面考虑算(ans_1),也就是全局
将操作拍成一个序列,一个显然的贪心是放(w_i)后取出(sumlimits_{vin son_i}w_v),相当于到一个点(i)时,(A_i=+w_i-sumlimits_{vin son_i}w_v),求最大前缀和
这样会发生一个问题,就是怎么构造这个序列,先选完儿子才能选父亲,很不好搞
这样转换:把操作序列倒过来看,就是先选父亲,才能选儿子节点。
之前比如在相对序列中儿子值的变化:({son_1(+w_{1}),...,son_2(+w_{2}),...,son_3(+w_3),...fa(-w_1-w_2-w_3)})
现在等价于:({fa(+w_1+w_2+w_3)},...,son_3(-w_3),...,son_2(-w_2),...,son_1(-w_1))
对于序列上的某个点(i),定义二元组((+sumlimits_{vin son_i}w_v-w_i,+sumlimits_{vin son_i}w_v))表示经过该点后的增量、历史最大增量
合并是显然的:((x,y)+(x',y')=(x+x',max(y,x+y')))
然后这样的二元组是有严格的优先级的:
- (x<0)的,优先放前面;多个(x<0)的,(y)较小的放前面
- ((x,y),(x',y')(x,x'>0)),((x,y))放前面当且仅当:(max(y,x+y')<max(y',x'+y)),由于(x,x'>0),等价于(x+y'<x'+yLongrightarrow x-y<x'-y')
做全局解后,显然某个子树的解序列是全局解的子序列,如果我们能得到全局解序列,那么通过线段树合并容易计算每个点的答案
然后贪心的做这个:
当取出的点(i)其父亲还没取出来时,令其与父亲合并
我们需要得到全局解,要用链表维护
Code
上面讲的可能有点不清楚,放份代码帮助理解一下
#include<bits/stdc++.h>
typedef long long LL;
#define pb push_back
#define opt operator
#define pii std::pair<LL,LL>
const LL maxn=2e5+9;
LL Read(){
LL x(0),f(1); char c=getchar();
while(c<'0' || c>'9'){
if(c=='-') f=-1; c=getchar();
}
while(c>='0' && c<='9'){
x=(x<<3ll)+(x<<1ll)+c-'0'; c=getchar();
}return x*f;
}
namespace Uf{
LL fa[maxn];
void Init(LL N){
for(LL i=1;i<=N;++i) fa[i]=i;
}
LL Find(LL x){
return fa[x]==x?x:fa[x]=Find(fa[x]);
}
}
struct node{
LL x,y,id;
bool opt < (const node A)const{
if(x<0 && A.x>=0) return 1;
if(A.x<0 && x>=0) return 0;
if(x<0 && A.x<0){
return (y<A.y || (y==A.y && id<A.id));
}
LL xx(y-x),yy(A.y-A.x);
return (xx>yy || (xx==yy && id<A.id));
}
node opt + (const node A)const{
return (node){x+A.x,std::max(y,x+A.y),id};
}
};
namespace Sgt{
LL nod;
LL rt[maxn],son[maxn*20][2];
node val[maxn*20];
void Modify(LL &nw,LL l,LL r,LL x,node v){
nw=++nod; val[nw]=v;
if(l==r){
return;
}
LL mid(l+r>>1);
if(x<=mid) Modify(son[nw][0],l,mid,x,v);
else Modify(son[nw][1],mid+1,r,x,v);
}
LL Merge(LL x,LL y){
if(!x || !y) return x|y;
son[x][0]=Merge(son[x][0],son[y][0]);
son[x][1]=Merge(son[x][1],son[y][1]);
val[x]=val[son[x][0]]+val[son[x][1]];
return x;
}
}
LL n,tot,T;
LL ans[maxn],val[maxn],w[maxn],nxt[maxn],head[maxn],tail[maxn],vis[maxn];
LL pos[maxn],fa[maxn];
node a[maxn];
std::vector<LL> V[maxn];
void Dfs(LL u){
Sgt::Modify(Sgt::rt[u],1,n,pos[u],(node){val[u]-w[u],val[u]});
for(LL i=0;i<V[u].size();++i){
LL v(V[u][i]);
Dfs(v);
Sgt::rt[u]=Sgt::Merge(Sgt::rt[u],Sgt::rt[v]);
}
ans[u]=Sgt::val[Sgt::rt[u]].y+w[u];
}
std::set<node> Set;
std::set<node>::iterator it1;
void Init(){
for(LL i=1;i<=n;++i){
val[fa[i]]+=w[i];
}
for(LL i=1;i<=n;++i){
a[i]=(node){val[i]-w[i],val[i],i};
Set.insert(a[i]);
head[i]=i; tail[i]=i;
}
Uf::Init(n);
}
void Update(LL u){
LL x(head[u]);
while(x){
++tot; pos[x]=tot;
vis[x]=1;
x=nxt[x];
}
}
void Merge(LL f,LL u){
Uf::fa[u]=f;
nxt[tail[f]]=head[u];
tail[f]=tail[u];
it1=Set.find(a[f]); Set.erase(it1);
a[f]=a[f]+a[u];
Set.insert(a[f]);
}
void Solve(){
memset(vis,0,sizeof(vis));
vis[0]=1;
while(!Set.empty()){
it1=Set.begin(); Set.erase(it1);
LL u((*it1).id),f(Uf::Find(fa[u]));
if(vis[f]){
Update(u);
}else{
Merge(f,u);
}
}
}
int main(){
T=Read();
n=Read();
for(LL i=2;i<=n;++i){
LL x(Read());
fa[i]=x; V[x].pb(i);
}
for(LL i=1;i<=n;++i){
w[i]=Read();
}
Init();
Solve();
Dfs(1);
for(LL i=1;i<=n;++i) printf("%lld ",ans[i]);
puts("");
return 0;
}