首页 > 代码库 > HZAU 1203 One Stroke(倍增)

HZAU 1203 One Stroke(倍增)

题目链接: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\n",ans==0?-1:ans);
    }
    return 0;
}

 

HZAU 1203 One Stroke(倍增)