Codeforces Round447 D树上前缀和
Posted amitherblogs
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round447 D树上前缀和相关的知识,希望对你有一定的参考价值。
已知完全二叉树和每条边的权值,q次询问,每次给出sta起点和H。
w=(H-点到sta的权值),求w>0的所有w的加和。
这题用树上前缀和来写,e[i]记录子树上的点到点i的距离,sum[i][j]为e[i]的前缀和
这样每次找到满足大于h-len[i]的长度就行(二分查找)
void init(){ for(ll x=n;x>=1;x--){ e[x].push_back(0); ll lc=x<<1;ll rc=x<<1|1; if(lc<=n){ for(int i=0;i<e[lc].size();i++){ e[x].push_back(e[lc][i]+len[lc-1]); } } if(rc<=n){ for(int i=0;i<e[rc].size();i++){ e[x].push_back(e[rc][i]+len[rc-1]); } } sort(e[x].begin(),e[x].end()); sum[x].resize(e[x].size()); for(int i=1;i<e[x].size();i++){ sum[x][i]=sum[x][i-1]+e[x][i]; } } } ll query(int x,ll h){ if(h<=0)return 0; int index=upper_bound(e[x].begin(),e[x].end(),h)-e[x].begin(); return index*h-sum[x][index-1]; } int main() { // freopen("in.txt","r",stdin); int m; scanf("%d%d",&n,&m); for(int i=1;i<n;i++){ scanf("%lld",&len[i]); } init(); while(m--){ ll a; ll h; ll pre=0; scanf("%lld%lld",&a,&h); ll ans=0; while(a&&h>0){ ans+=h; ll lc=a<<1; ll rc=a<<1|1; if(lc!=pre&&lc<=n){ ans+=query(lc, h-len[lc-1]); } // cout<<ans<<" "; if(rc!=pre&&rc<=n){ ans+=query(rc, h-len[rc-1]); } //cout<<ans<<" "; h-=len[a-1]; pre=a; a/=2; } printf("%lld ",ans); } }
以上是关于Codeforces Round447 D树上前缀和的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #480 (Div. 2) C 贪心 D 数字思维 E 树上倍增
Codeforces Round #643 (Div. 2) (A模拟+B贪心+C(差分数组+前缀和/枚举)+D(思维))
Codeforces Round #384 (Div. 2)