link
sol
看完题目我们很容易可以写出一个 \(DP\) ,定义 \(f_i\) 表当前询问的最优解
\[f_u=a_u+x+\sum max(f_v,0)
\]
其中 \(v\) 是 \(u\) 的儿子
然后考虑怎么算这个东西
思考每一个状态的时候肯定是一个森林
如果 \(x\) 不断递增,那么只可能建边,不可能删边
所以将问题离线下来,\(x\) 从小到大处理
于是柿子就变成了
\(f_u=a_u+x+\sum f_v\)
于是对于一个 \(x\) 的答案就是当前这个数的(注意不是原树) \(size\times val +sum\)
所以对于一个节点只需要维护 \(size\) 和 \(sum\) 两个量就可以了
考虑建边的条件,就是 \(sz \times t+sum ≥0\)
于是 $t=\lceil \frac{sum}{size} \rceil $
开一个堆记录一下 \(t\) 的最大值,每次将小于 \(x\) 的边建上
最后思考建边的时候如何修改 \(size\) 和 \(sum\)
我们求出 \(dfs\) 序,将树上问题转化到序列问题
我们发现连接的时候其实是维护向上一串链的 \(sum\) 和 \(size\)
于是就变成了一个区间改 + 点查的问题,用树状数组可以处理出来
开两个树状数组,一个 \(sum\) 一个记 \(size\),最后用\(size\times val +sum\)就好了
code
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=1e6+5,maxe=2e6+5;
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
LL ans[maxn];
int N,M,a[maxn];
int lnk[maxn],nxt[maxe],son[maxe],cnt;
inline void add_e(int x,int y){son[++cnt]=y;nxt[cnt]=lnk[x];lnk[x]=cnt;}
int vis[maxn],now,f[maxn],fa[maxn];
struct que{
int x;LL y;int id;
bool operator <(const que B)const {return y<B.y;}
}Q[maxn];
struct Bit{
LL c[maxn];
void add_x(int x,LL data){
for(int i=x;i<=N;i+=i&-i)c[i]+=data;
}
LL get(int x){
LL ret=0;
for(int i=x;i;i-=i&-i)ret+=c[i];
return ret;
}
}S,T;
int dfn[maxn],bg[maxn],ed[maxn];
struct node{
LL w;
int id;
bool operator <(const node B)const {return w>B.w;}
};
priority_queue<node> q;
void dfs(int x){
bg[x]=++bg[0];
for(int j=lnk[x];j;j=nxt[j]) dfs(son[j]);
ed[x]=bg[0];
return ;
}
LL getsiz(int x){return S.get(ed[x])-S.get(bg[x]-1)+1;}
LL getval(int x){return T.get(ed[x])-T.get(bg[x]-1)+a[x];}
LL getans(int x){return getval(x)+getsiz(x)*now;}
int getfa(int x){
return f[x]==x?x:f[x]=getfa(f[x]);
}
void get(int x){
vis[x]=1;f[x]=fa[x];LL s=getsiz(x),t=getval(x);
int fx=getfa(x);if(fa[fx]) S.add_x(bg[fa[fx]],-s),T.add_x(bg[fa[fx]],-t);
if(fa[x]) S.add_x(bg[fa[x]],s),T.add_x(bg[fa[x]],t);
if(!fx)return ;
s=getans(fx);
if(s>0)return get(fx);q.push((node){now+(-s-1)/getsiz(fx)+1,fx});
return ;
}
int main(){
freopen("D.in","r",stdin);
freopen("D.out","w",stdout);
N=read();M=read();
for(int i=2;i<=N;i++) add_e(fa[i]=read(),i);
for(int i=1;i<=N;i++) a[i]=read(),f[i]=i;
for(int i=1;i<=M;i++) Q[i].x=read(),Q[i].y=read(),Q[i].id=i;
dfs(1);sort(Q+1,Q+1+M);
for(int i=1;i<=N;i++) q.push((node){-a[i],i});
for(int i=1;i<=M;i++){
now=Q[i].y;
while(!q.empty()){
node Top=q.top();
if(Top.w>now)break;
q.pop();
if(!vis[Top.id])get(Top.id);
}
ans[Q[i].id]=getans(Q[i].x);
}
for(int i=1;i<=M;i++)
printf("%lld\n",ans[i]);
return 0;
}