题解:洛谷 P8218 求区间和

【题目来源】

洛谷:P8218 【深进1.例1】求区间和 - 洛谷

【题目描述】

给定 \(n\) 个正整数组成的数列 \(a_1, a_2, \cdots, a_n\)\(m\) 个区间 \([l_i,r_i]\),分别求这 \(m\) 个区间的区间和。

对于所有测试数据,\(n,m\le10^5,a_i\le 10^4\)

【输入】

第一行,为一个正整数 \(n\)

第二行,为 \(n\) 个正整数 \(a_1,a_2, \cdots ,a_n\)

第三行,为一个正整数 \(m\)

接下来 \(m\) 行,每行为两个正整数 \(l_i,r_i\) ,满足\(1\le l_i\le r_i\le n\)

【输出】

\(m\) 行。

\(i\) 行为第 \(i\) 组答案的询问。

【输入样例】

4
4 3 2 1
2
1 4
2 3

【输出样例】

10
5

【核心思想】

  1. 问题分析:给定长度为 \(n\) 的正整数序列 \(a_1, a_2, \dots, a_n\),以及 \(m\) 个区间查询 \([l_i, r_i]\),需要依次输出每个区间内所有元素之和。由于 \(n, m \le 10^5\),若每次暴力求和会超时,需利用预处理将区间和查询优化为 \(O(1)\) 操作。

  2. 算法选择

    • 前缀和:预处理前缀和数组 \(S[i] = \sum_{k=1}^{i} a_k\)\(1 \le i \le n\)),则区间 \([l, r]\) 的和为 \(S[r] - S[l-1]\)。预处理 \(O(n)\),每次查询 \(O(1)\),总时间复杂度 \(O(n+m)\),空间复杂度 \(O(n)\)
  3. 关键步骤

    • 读入 \(n\) 和数组 \(a[1..n]\)
    • 计算前缀和数组 \(s[0] = 0\),对于 \(i=1..n\)\(s[i] = s[i-1] + a[i]\)
    • 读入 \(m\),对每个查询 \((l, r)\),输出 \(s[r] - s[l-1]\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n + m)\),预处理 \(O(n)\),每次查询 \(O(1)\)
    • 空间复杂度:\(O(n)\),存储前缀和数组。
  5. 前缀和的核心思想

    • 通过预计算前缀和,将子数组求和问题转化为两个前缀和的差,消除重复计算。
    • 适用于静态数组的多次区间和查询,是处理区间统计问题的基础技巧。
    • 可推广到二维前缀和、差分数组等更复杂的场景。

【算法标签】

普及- #前缀和

【代码详解】

#include <bits/stdc++.h>
using namespace std;

const int MAX_N = 100005;  // 定义数组最大长度
int n, m;                   // n: 数组长度, m: 查询次数
int a[MAX_N];               // 存储原始数组
int s[MAX_N];               // 存储前缀和数组

int main()
{
    // 输入数组长度
    cin >> n;

    // 输入数组元素并计算前缀和
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        s[i] = s[i - 1] + a[i];  // 前缀和公式:s[i] = s[i-1] + a[i]
    }

    // 输入查询次数
    cin >> m;

    // 处理每个查询
    for (int i = 1; i <= m; i++)
    {
        int l, r;  // 查询区间[l, r]
        cin >> l >> r;

        // 输出区间和:s[r] - s[l-1]
        cout << s[r] - s[l - 1] << endl;
    }

    return 0;
}
// 使用acwing模板二刷
#include <bits/stdc++.h>
using namespace std;

const int N = 100005;  // 定义数组最大长度
int n, m;              // n: 数组长度, m: 查询次数
int a[N];              // 原始数组
int s[N];              // 前缀和数组

int main()
{
    // 输入数组长度
    cin >> n;

    // 输入数组元素
    for (int i = 1; i <= n; i++)
        cin >> a[i];

    // 计算前缀和数组
    for (int i = 1; i <= n; i++)
        s[i] = s[i - 1] + a[i];  // s[i] = 前i项的和

    // 输入查询次数
    cin >> m;

    // 处理每个查询
    while (m--)
    {
        int l, r;  // 查询区间[l, r]
        cin >> l >> r;

        // 输出区间和:s[r] - s[l-1]
        cout << s[r] - s[l - 1] << endl;
    }

    return 0;
}

【运行结果】

4
4 3 2 1
2
1 4
10
2 3
5
posted @ 2026-09-02 21:41  团爸讲算法  阅读(19)  评论(0)    收藏  举报