【完全二叉树的权值】

题目

代码1(队列)

#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int, int> PII;

const int N = 1e5+10;
int n;
long long a[N];
queue<PII> q;
long long sum[25];
int main()
{
    memset(sum, -1, sizeof(long long) * 25);
    
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    
    q.push({1, 1});
    while(!q.empty())
    {
        int fr = q.front().x;
        int deep = q.front().y;
        if(sum[deep] == -1) sum[deep] = 0;
        sum[deep] += a[fr];
        
        int left = 2 * fr;
        int right = 2 * fr + 1;
        
        if(left <= n)
        {   
            q.push({left, deep+1});
        }
        if(right <= n)
        {
            q.push({right, deep+1});
        }
        
        q.pop();
    }
    
    long long MAX = LLONG_MIN, mdeep;
    for(int i = 1; i <= 20; i++)
    {
        if(sum[i] != -1 && sum[i] > MAX) //sum[i]有负数,而且不知道i的具体范围,初始化又是0,所以需要用-1初始化
        {
            MAX = sum[i];
            mdeep = i;
        }
    }
    
    cout << mdeep;
    
    return 0;
}

代码2(前缀和)

#include <iostream>

// 使用命名空间 std,这样就可以不用每次调用 std:: 来访问标准库函数
using namespace std;

// 定义一个别名 LL,它代表 long long 类型,通常用于表示大整数
typedef long long LL;

// 定义一个常量 N,其值为 100010,作为数组的最大长度
const int N = 100010;

// 定义全局变量
// a[] 数组存储输入的整数序列
// id 用来记录答案中子数组的深度
// n 为整数序列的长度
// ans 用来记录当前找到的最大和,初始化为 INT_MIN
// s[] 数组用于存储前缀和
int a[N], id, n;
LL ans = INT_MIN, s[N];

// 主函数
int main()
{
    // 读入整数序列的长度 n
    cin >> n;
    // 读入整数序列并存入 a[] 数组
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    // 计算前缀和 s[]
    for (int i = 1; i <= n; i++)
        s[i] = s[i - 1] + a[i];

    // 遍历每个可能的子数组长度,从 2 开始,每次翻倍直到超过 n
    // j 为当前子数组的起始位置
    // depth 表示子数组的 "深度",即进行了几次翻倍操作
    for (int i = 2, j = 1, depth = 1; j <= n; j = i, i *= 2, depth++)
    {
        // 确保 i 不会越界
        i = min(i, n + 1);
        // 如果当前子数组的和大于之前找到的最大和,则更新 ans 和 id
        if (ans < s[i - 1] - s[j - 1])
        {
            ans = s[i - 1] - s[j - 1];
            id = depth;
        }
    }
    // 输出答案中子数组的深度
    cout << id << endl;

    return 0;
}

上面这个抓住前缀和的r用下一层深度的第一个节点来算r = i-1,l就是当前深度的第一个节点。

因此i的迭代用i*=2,j滞后于i,j=i

对于根节点,s[1] - s[0],r = 1, l = 0,令i = 2, j = 1。

因为这个是完全二叉树,最后一层不一定满,因此最后一个i应该要强制规定到n+1。而j一定是某层第一个节点。最后一次j必定为n+1,所以只要控制 j <= n,以此作循环持续标志就行。

代码3(双指针,其实就是没有前缀和而已)

#include <bits/stdc++.h>

// 使用命名空间 std,这样就可以不用每次调用 std:: 来访问标准库函数
using namespace std;

// 定义一个别名 LL,它代表 long long 类型,通常用于表示大整数
typedef long long LL;

// 定义一个常量 N,其值为 100010,作为数组的最大长度
const int N = 100010;

// 定义全局变量
// a[] 数组存储输入的整数序列
// id 用来记录答案中子数组的深度
// n 为整数序列的长度
// ans 用来记录当前找到的最大和,初始化为 INT_MIN
// s[] 数组用于存储前缀和
int a[N], id, n;
LL ans = INT_MIN;

// 主函数
int main()
{
    // 读入整数序列的长度 n
    cin >> n;
    // 读入整数序列并存入 a[] 数组
    for (int i = 1; i <= n; i++)
        cin >> a[i];

    // 遍历每个可能的子数组长度,从 2 开始,每次翻倍直到超过 n
    // j 为当前子数组的起始位置
    // depth 表示子数组的 "深度",即进行了几次翻倍操作
    for (int i = 2, j = 1, depth = 1; j <= n; j = i, i *= 2, depth++)
    {
        // 确保 i 不会越界
        i = min(i, n + 1);
        LL s = 0;
        // 计算从 j 到 i - 1 的所有元素之和
        for(int m = j; m <= i-1; m++) s += a[m];
        // 如果当前子数组的和大于已有的最大值,则更新最大值和深度
        if(ans < s)
        {
            ans = s;
            id = depth;
        }
    }
    // 输出答案中子数组的深度
    cout << id << endl;

    return 0;
}

  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值