题目链接:http://acm.hzau.edu.cn/problem.php?id=1203
【题意】给你一颗完全二叉树每个节点都有一个权值,然后要你从上往下找一条链,值得链上权值的和<K,且节点数最大。
【分析】有两种做法:一种是在树上双指针,另一种是先求一下前缀和,当到i节点时前缀和<K,更新ans,当前缀和>K,倍增向上找
使得前缀和<K的节点,更新ans。
#include <bits/stdc++.h> #define inf 100000000 #define met(a,b) memset(a,b,sizeof a) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 typedef long long ll; using namespace std; const int N = 1e6+5; const int M = 4e5+5; int n,m,ans; int a[N]; int sum[N],fa[N][22],dep[N]; void dfs(int u,int f){ if(u>n)return; sum[u]=sum[f]+a[u]; dep[u]=dep[f]+1; fa[u][0]=f; for(int i=1;i<22;i++)fa[u][i]=fa[fa[u][i-1]][i-1]; if(sum[u]<=m)ans=max(ans,dep[u]); else { int v=u; for(int i=21;i>=0;i--){ if(sum[u]-sum[fa[v][i]]<=m){ ans=max(ans,dep[u]-dep[fa[v][i]]); v=fa[v][i]; } } } dfs(u*2,u); dfs(u*2+1,u); } int main() { int T,op,x,y,v; scanf("%d",&T); for(int cas=1;cas<=T;cas++){ met(fa,0); ans=0; met(sum,0); met(dep,0); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } dfs(1,0); printf("%d ",ans==0?-1:ans); } return 0; }