传送门
题解:
加入一个数,相当于是先加上 A i = w i A_i=w_i Ai=wi,再减去 B i = ∑ j ∈ s o n i w j B_i = \sum_{j \in son_i} w_j Bi=∑j∈soniwj,然后代价就是一个操作序列的前缀最大值。
先考虑一下没有限制的的时候,怎么使得这个前缀最大值最小,我们可以分为两个部分: A i − B i < 0 , A i − B i ≥ 0 A_i - B_i \lt 0,A_i -B_i \ge 0 Ai−Bi<0,Ai−Bi≥0。显然 A i − B i < 0 A_i - B_i \lt0 Ai−Bi<0的要放在 A i − B i ≥ 0 A_i -B_i \ge 0 Ai−Bi≥0的前面。 先考虑 A i − B i < 0 A_i -B_i \lt 0 Ai−Bi<0。
此时我们假设一个二分值 T T T,那么每次就是把 A i A_i Ai小等于某个值里面最小的那个拿出来,然后继续这个过程,于是我们只需要按照 A i A_i Ai从小到大排序即可。 A i − B i ≥ 0 A_i - B_i \ge 0 Ai−Bi≥0的相当于使得后缀最小值最大,就是反过来的前缀最大值最小,其实就是按照 B i B_i Bi从大到小排序。
然后考虑有限制怎么办,我们也把这个过程反过来,看作是从根开始选,每次加上 ∑ j ∈ s o n i w j \sum_{j \in son_i}w_j ∑j∈soniwj再减去 w i w_i wi。 这个时候我们会发现最小的那个值一定在父亲选了之后马上选,我们可以用个堆维护一下,每次把最小的和父亲合并起来,这样就可以得到选择的顺序了(每个子树的顺序是其子序列)。
然后知道了序列长啥样,剩下的就是一个线段树合并了,时间复杂度 O ( n log n ) O(n \log n) O(nlogn)。
#include
using namespace std;
typedef long long LL;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
inline void W(LL x) {
static int buf[50];
if(!x) {putchar('0'); return;}
if(x<0) {putchar('-'); x=-x;}
while(x) {buf[++buf[0]]=x%10; x/=10;}
while(buf[0]) putchar(buf[buf[0]--]+'0');
}
const int N=2e5+50;
int n,w[N],p[N],fa[N],anc[N],tot;
LL s[N],w2[N],ans[N];
int rt[N],lc[N*30],rc[N*30];
LL sw[N*30],mx[N*30];
vector <int> son[N];
inline void upt(int x) {
sw[x]=sw[lc[x]]+sw[rc[x]];
mx[x]=max(mx[lc[x]],sw[lc[x]]+mx[rc[x]]);
}
inline void inc(int &k,int l,int r,int p,int w,LL v) {
if(!k) k=++tot;
if(l==r) {sw[k]=w-v; mx[k]=w; return;}
int mid=(l+r)>>1;
(p<=mid) ? inc(lc[k],l,mid,p,w,v) : inc(rc[k],mid+1,r,p,w,v);
upt(k);
}
inline int merge(int x,int y) {
if(!x) return y;
if(!y) return x;
lc[x]=merge(lc[x],lc[y]);
rc[x]=merge(rc[x],rc[y]);
upt(x); return x;
}
inline void dfs(int x) {
for(auto v:son[x])
dfs(v), rt[x]=merge(rt[x],rt[v]);
ans[x]=max(mx[rt[x]],sw[rt[x]]+w[x]);
inc(rt[x],1,n,p[x],w[x],s[x]);
}
struct Que {
deque <int> *q;
inline void init(int i) {q=new deque <int>; q->push_back(i);}
inline void merge(Que &b) {
if(q->size()<b.q->size()) {
swap(q,b.q);
for(int i=b.q->size()-1;~i;i--) q->push_front(b.q->operator[](i));
} else {
for(int i=0;i<b.q->size();i++) q->push_back(b.q->operator[](i));
} delete b.q;
}
} q[N];
struct cmp {
inline bool operator ()(int x,int y) {
if(w2[x]<0 && w2[y]>=0) return true;
if(w2[x]>=0 && w2[y]<0) return false;
if(w2[x]<0) return (s[x]<s[y] || (s[x]==s[y]&&x<y));
else return (w2[x]-s[x]>w2[y]-s[y] || (w2[x]-s[x]==w2[y]-s[y]&&x<y));
}
};
set <int,cmp> S;
inline int ga(int x) {return (anc[x]==x) ? x : (anc[x]=ga(anc[x]));}
int main() {
rd(); n=rd();
for(int i=2;i<=n;i++) son[fa[i]=rd()].push_back(i);
for(int i=1;i<=n;i++) w[i]=rd();
for(int i=1;i<=n;i++) for(auto v:son[i]) s[i]+=w[v];
for(int i=1;i<=n;i++) q[i].init(i), anc[i]=i, w2[i]=s[i]-w[i], S.insert(i);
while(!S.empty()) {
int u=*S.begin(); S.erase(u);
if(!ga(fa[u])) {
for(auto v:*q[u].q) p[v]=n-tot++;
anc[u]=0;
} else {
anc[u]=fa[u];
S.erase(ga(u));
q[ga(u)].merge(q[u]);
s[ga(u)]=max(s[ga(u)],w2[ga(u)]+s[u]);
w2[ga(u)]=w2[ga(u)]+w2[u];
S.insert(ga(u));
}
}
for(int i=1;i<=n;i++) {
s[i]=0;
for(auto v:son[i]) s[i]+=w[v];
}
dfs(1);
for(int i=1;i<=n;i++) W(ans[i]), putchar(' ');
}