题意:一颗满二叉树n(1e6)个顶点,边权都知道,一共q(1e5)次询问.从ST点出发有生命值H,求dis(st,任意一点x)<=H 的 sgima(H-dis)
思路:
1.对于一个点,出发有三种情况,左儿子/右儿子/父亲,求是否能走到 以及 走到后有多少个可能的值(二分)
2.那么从ST出发一步一步往上走,就相当于是从ST出发
画图理解一下吧!
时间复杂度:[n(1+1/2+1/4+...)=O(n) ]+ O(nlogn * log(logn))+O(q*logn*log(logn))
这道题还要注意空间复杂度: nlogn n=1e6. 正常开会爆内存,开vector优化空间
#include<bits/stdc++.h> #define PI acos(-1.0) using namespace std; typedef long long ll; const int N=1e6+6; const int MOD=1e9+7; const int INF=0x3f3f3f3f; vector <int> ans[N]; vector <ll> sum[N]; int cost[N],h; int n,q,st,last; /// distance bewteen subtree root and subtree node void dfs(int now,int rt,int fdis){ if(now>n) return ; int lson=now*2,rson=now*2+1; if(lson<=n) ans[rt].push_back(cost[lson]+fdis),dfs(lson,rt,cost[lson]+fdis); if(rson<=n) ans[rt].push_back(cost[rson]+fdis),dfs(rson,rt,cost[rson]+fdis); } int main(void){ cin >> n>>q; for(int i=2;i<=n;i++) scanf("%d",&cost[i]); for(int i=1;i<=n;i++) ans[i].push_back(0),dfs(i,i,0); for(int i=1;i<=n;i++){ sort(ans[i].begin(),ans[i].end()); sum[i].resize((int)ans[i].size()+1,0); for(int j=1;j<(int)ans[i].size();++j){ sum[i][j]+=sum[i][j-1]+1ll*ans[i][j]; } } // for(int i=1;i<=n;i++){ // printf("%d: ",i); // for(auto j : ans[i]) printf("%lld ",j); // cout<<endl; // for(auto j : sum[i]) printf("%lld ",j.second);puts("*************"); // } for(int i=1;i<=q;i++){ scanf("%d%d",&st,&h); ll res=0; while(st>0 && h>0){ res+=1ll*h; int lson=st*2; int rson=st*2+1; if(last!=lson && lson<=n){ int te=h-cost[lson]; // cout <<"te="<<te<<endl; if(te>0){ res+=te; // cout <<"te1="<<te<<endl; int pos=prev(lower_bound(ans[lson].begin(),ans[lson].end(),te))-ans[lson].begin(); // cout <<"pos="<<pos<<endl; res+= (1ll*pos*te-sum[lson][pos]); } // cout <<"rse1="<<res<<endl; } if(last!=rson && rson<=n){ int te=h-cost[rson]; if(te>0){ res+=te; int pos=prev(lower_bound(ans[rson].begin(),ans[rson].end(),te))-ans[rson].begin(); res+= (1ll*pos*te-sum[rson][pos]); } // cout <<"rse2="<<res<<endl; } last=st; h-=cost[last]; // cout <<"h="<<h<<endl; st/=2; // cout <<"st="<<st<<endl; } cout << res << endl; } return 0; } /********* 6 4 2 1 1 3 2 1 3 *********/