codeforces 894 D (DS)

来源:互联网 发布:淘宝自动刷手软件安卓 编辑:程序博客网 时间:2024/06/05 15:09

题目链接

D. Ralph And His Tour in Binary Country

分析

由于给出的是完全二叉树,那么我们可以预处理每颗子树的路径和,这样查询的时候就只需往上走 log n 次就行了. 考虑合并的时候就可以只用把两个儿子节点用归并排序的思路合并就行. 我用的是库函数.

比较trick 的是查询,开始一直没懂怎么查询

我们从查询节点往父亲方向走,那么包含查询节点的子子树已经查询完比,因此只需对它父亲节点的兄弟的子树查询就行,相应的处理一下当前查询值.

#include <bits/stdc++.h>using namespace std;#define ms(x,v) (memset((x),(v),sizeof(x)))#define pb push_back#define mp make_pair#define fi first#define se second#define INF 0x3f3f3f3f#define INF64 0x3f3f3f3f3f3f3f3ftypedef long long LL;typedef pair<int,int > Pair;const int MOD = 1e9+7;const int maxn = 1e6+10;int n,q,w[maxn];std::vector<LL> sum[maxn],g[maxn];inline LL value(int v,LL h){   if(v>n)return 0;   int p = lower_bound(g[v].begin(),g[v].end(),h) - g[v].begin();   return h*(p) - sum[v][p];}int main(int argc, char const *argv[]) {   cin>>n>>q;   for(int i=2 ; i<=n ; ++i)scanf("%d",w+i );   for(int i=1 ; i<=n ; ++i)g[i].pb(0);   std::vector<LL> tmp[2];   for(int i=n ; i>=1 ;--i ){      sum[i].resize(g[i].size()+1);      for(int j=0 ; j<g[i].size() ; ++j)sum[i][j+1] = sum[i][j] + g[i][j];      if(!(i&1)){         tmp[0].resize(g[i].size());tmp[1].resize(g[i+1].size());         for(int j=0 ; j<g[i].size() ; ++j)tmp[0][j] = g[i][j]+w[i];         for(int j=0 ; j<g[i+1].size() ; ++j)tmp[1][j] = g[i+1][j]+w[i+1];         g[i/2].resize(g[i].size()+g[i+1].size()+1);g[i/2][0]=0;         merge(tmp[0].begin(),tmp[0].end(),tmp[1].begin(),tmp[1].end(),g[i/2].begin()+1);      }   }   while (q--) {      int v;LL h;      scanf("%d%lld",&v,&h );      LL ans = value(v,h);      while (v>1) {         h-=w[v];         if(h<0)break;         ans += h + value(v^1,h-w[v^1]);         v >>=1;      }      printf("%lld\n",ans );   }    return 0;}
原创粉丝点击