题解:
看网上的做法都十分的迷。就来水一篇博客吧。
记 f[i][j] f [ i ] [ j ] 表示遍历以 i i 为根的子树,最后以结尾的最小代价。
注意这是 O(nlogn) O ( n log n ) 的,因为每个点只有 logn log n 个父亲。
处理这个数组也十分Naive,只需要在每个点分别枚举先进入左子树还是右子树,然后最后从哪个节点进入另一个子树即可。这也是 O(nlogn) O ( n log n ) 的。
然后处理出 g[i] g [ i ] 表示处理完 i i 的子树并跳到的爷爷的最小代价。
枚举每个点,用 dp d p 数组来优化模拟的过程,暴力往上跳就行了。
#include <bits/stdc++.h>
typedef long long LL;
using namespace std;
inline int rd() {
char ch=getchar(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=getchar();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=getchar();}
return i*f;
}
const int N=2e5+50;
const LL INF=0x3f3f3f3f3f3f3f3f;
int n;
LL a[N],f[N][20],g[N];
LL dis[N],dep[N];
vector <int> l_leaf[N];
vector <int> r_leaf[N];
vector <int> son[N];
int main() {
n=rd();
for(int i=1;i<=n;i++) a[i]=rd();
for(int i=1;i<n;i++) {
int fa=(i+1)/2,now=i+1;
dep[now]=dep[fa]+1;
dis[now]=dis[fa]+rd();
son[fa].push_back(now);
if((now<<1)>n) {
int lst=now,x=now>>1;
while(x) {
if(lst&1) r_leaf[x].push_back(now);
else l_leaf[x].push_back(now);
lst=x; x=x>>1;
}
}
}
for(int i=n;i>=1;i--) {
if(!son[i].size()) f[i][dep[i]]=0;
else if(son[i].size()==1) {
int lc=son[i][0]; LL v=(dis[lc]-dis[i])*a[lc];
for(int e=l_leaf[i].size()-1;e>=0;e--) {
int x=l_leaf[i][e]; f[x][dep[i]]=f[x][dep[i]+1]+v;
}
} else {
int lc=son[i][0],rc=son[i][1];
LL L_min=INF,R_min=INF,Lv=(dis[lc]-dis[i])*a[lc],Rv=(dis[rc]-dis[i])*a[rc];
for(int e=l_leaf[i].size()-1;e>=0;e--) {
int x=l_leaf[i][e]; L_min=min(L_min,f[x][dep[i]+1]+Lv+(dis[x]+dis[rc]-2*dis[i])*a[rc]);
}
for(int e=r_leaf[i].size()-1;e>=0;e--) {
int x=r_leaf[i][e]; R_min=min(R_min,f[x][dep[i]+1]+Rv+(dis[x]+dis[lc]-2*dis[i])*a[lc]);
}
for(int e=l_leaf[i].size()-1;e>=0;e--) {
int x=l_leaf[i][e]; f[x][dep[i]]=R_min+f[x][dep[i]+1];
}
for(int e=r_leaf[i].size()-1;e>=0;e--) {
int x=r_leaf[i][e]; f[x][dep[i]]=L_min+f[x][dep[i]+1];
}
}
} memset(g,0x3f,sizeof(g));
for(int i=n;i>=1;i--) {
if(son[i].size()) break;
int now=i;
while(dep[now]>=1) {
g[now]=min(g[now],f[i][dep[now]]+((dep[now]>=2)?(dis[i]-dis[now>>2])*a[now>>2]:0));
now>>=1;
}
} LL ans=INF;
for(int i=n;i>=1;i--) {
if(son[i].size()) break;
ans=min(ans,f[i][0]);
}
for(int i=2;i<=n;i++) {
LL rs=0,mx=INF;
if(!son[i].size()) mx=(dis[i]-dis[i>>1])*a[i>>1];
else {
for(int e=l_leaf[i].size()-1;e>=0;e--) mx=min(mx,f[l_leaf[i][e]][dep[i]]+(dis[l_leaf[i][e]]-dis[i>>1])*a[i>>1]);
for(int e=r_leaf[i].size()-1;e>=0;e--) mx=min(mx,f[r_leaf[i][e]][dep[i]]+(dis[r_leaf[i][e]]-dis[i>>1])*a[i>>1]);
} rs+=mx;
int lst=i,now=i>>1;
while(now) {
if(!l_leaf[now].size() || !r_leaf[now].size()) {
if(now!=1) rs+=(dis[now]-dis[now>>1])*a[now>>1];
} else {
int t=(son[now][0]==lst)?son[now][1]:son[now][0];
rs+=(dis[t]-dis[now])*a[t];
rs+=g[t];
} lst=now; now=now>>1;
}
ans=min(ans,rs);
} printf("%lld\n",ans);
}