{ }codelper
前缀和64 位整数P0039

快速求区间和

给出由 n 个整数组成的数列 a_1, a_2, …, a_n 和 q 个询问。
每个询问由两个数 l、r 组成,询问 a_l 到 a_r(含两端)的和。
按询问给出的顺序,每个询问输出一行答案。
第一行是 n 和 q,第二行是 a_1 … a_n,接下来 q 行每行是用空格分隔的 l 和 r。

输入
1 ≤ n ≤ 10,000,1 ≤ q ≤ 20,000,-10^9 ≤ a_i ≤ 10^9,1 ≤ l ≤ r ≤ n
输出
q 行,每行是该询问的区间和
样例 1 · stdin
5 3
3 -1 4 1 -5
1 3
2 5
4 4
stdout
6
-1
1
main.py
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 8 种语言题解

每个询问都从 l 加到 r,最多要做 10^4 × 2×10^4 = 2×10^8 次加法,Python 无法在时限内完成(C、C++ 暂时还撑得住,但 n、q 再大也一样不行)。
Craykon 在执行步数超过约 5 千万次时会以“运行太久”停止,所以这种写法无论机器多快都会超时。
先构造一次前缀和 P[i] = a_1 + … + a_i(P[0] = 0),答案就是 P[r] - P[l-1]。
常见错误:写成 P[r] - P[l] 漏掉 a_l;以及和最大可达 10^13,却在 C、C++、Java、C# 中存进 int(约 21 亿)——要用 long/long long。
Python 整数无上限,JavaScript、TypeScript、Craykon 在 2^53 以内精确,所以没问题。
输入量大,Python 用 sys.stdin,Java 用 BufferedReader,C++ 用 sync_with_stdio(false) 加快读取。
Craykon 的列表最多只能放 10,000 个,所以不建 n + 1 格的 P,而是用 a[i] = a[i] + a[i - 1] 把 a 原地变成前缀和,询问用 控制台.读数字() 一行一行读。

Pythonmain.py · 14 行
import sys data = sys.stdin.buffer.read().split()n, q = int(data[0]), int(data[1])prefix = [0] * (n + 1)  # prefix[i] = 앞에서 i개의 합for i in range(n):    prefix[i + 1] = prefix[i] + int(data[2 + i])out = []pos = 2 + nfor _ in range(q):    l, r = int(data[pos]), int(data[pos + 1])    pos += 2    out.append(prefix[r] - prefix[l - 1])print("\n".join(map(str, out)))
JavaScriptmain.js · 10 行
const t = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const [n, q] = t;const prefix = new Array(n + 1).fill(0); // prefix[i] = 앞에서 i개의 합for (let i = 0; i < n; i++) prefix[i + 1] = prefix[i] + t[2 + i];const out = [];for (let k = 0, pos = 2 + n; k < q; k++, pos += 2) {  const l = t[pos], r = t[pos + 1];  out.push(prefix[r] - prefix[l - 1]);}console.log(out.join("\n"));
TypeScriptmain.ts · 11 行
import { readFileSync } from "node:fs";const t: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const [n, q] = t;const prefix: number[] = new Array(n + 1).fill(0); // prefix[i] = 앞에서 i개의 합for (let i = 0; i < n; i++) prefix[i + 1] = prefix[i] + t[2 + i];const out: number[] = [];for (let k = 0, pos = 2 + n; k < q; k++, pos += 2) {  const l = t[pos], r = t[pos + 1];  out.push(prefix[r] - prefix[l - 1]);}console.log(out.join("\n"));
JavaMain.java · 22 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.StringTokenizer; public class Main {    public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        StringTokenizer st = new StringTokenizer(br.readLine());        int n = Integer.parseInt(st.nextToken()), q = Integer.parseInt(st.nextToken());        long[] prefix = new long[n + 1]; // prefix[i] = 앞에서 i개의 합        st = new StringTokenizer(br.readLine());        for (int i = 0; i < n; i++) prefix[i + 1] = prefix[i] + Long.parseLong(st.nextToken());        StringBuilder out = new StringBuilder();        for (int k = 0; k < q; k++) {            st = new StringTokenizer(br.readLine());            int l = Integer.parseInt(st.nextToken()), r = Integer.parseInt(st.nextToken());            out.append(prefix[r] - prefix[l - 1]).append('\n');        }        System.out.print(out);    }}
C#Main.cs · 21 行
using System;using System.IO;using System.Text; class Program{    static void Main()    {        string[] t = Console.In.ReadToEnd().Split((char[])null, StringSplitOptions.RemoveEmptyEntries);        int n = int.Parse(t[0]), q = int.Parse(t[1]);        long[] prefix = new long[n + 1]; // prefix[i] = 앞에서 i개의 합        for (int i = 0; i < n; i++) prefix[i + 1] = prefix[i] + long.Parse(t[2 + i]);        var sb = new StringBuilder();        for (int k = 0, pos = 2 + n; k < q; k++, pos += 2)        {            int l = int.Parse(t[pos]), r = int.Parse(t[pos + 1]);            sb.Append(prefix[r] - prefix[l - 1]).Append('\n');        }        Console.Write(sb);    }}
C++main.cpp · 20 行
#include <iostream>#include <vector> int main() {    std::ios::sync_with_stdio(false);    std::cin.tie(nullptr);    int n, q;    std::cin >> n >> q;    std::vector<long long> prefix(n + 1, 0); // prefix[i] = 앞에서 i개의 합    for (int i = 0; i < n; i++) {        long long x;        std::cin >> x;        prefix[i + 1] = prefix[i] + x;    }    for (int k = 0; k < q; k++) {        int l, r;        std::cin >> l >> r;        std::cout << prefix[r] - prefix[l - 1] << '\n';    }}
Cmain.c · 21 行
#include <stdio.h>#include <stdlib.h> int main(void) {    int n, q;    scanf("%d %d", &n, &q);    long long *prefix = malloc((n + 1) * sizeof *prefix); // prefix[i] = 앞에서 i개의 합    prefix[0] = 0;    for (int i = 0; i < n; i++) {        long long x;        scanf("%lld", &x);        prefix[i + 1] = prefix[i] + x;    }    for (int k = 0; k < q; k++) {        int l, r;        scanf("%d %d", &l, &r);        printf("%lld\n", prefix[r] - prefix[l - 1]);    }    free(prefix);    return 0;}
Craykonmain.cray · 23 行
첫줄 = 控制台.读数字();n = 첫줄[0];q = 첫줄[1];// a를 그 자리에서 누적 합으로 바꾼다: a[i] = 앞에서 i+1개의 합a = 控制台.读数字();循环 (i = 1; i < n; i++){    a[i] = a[i] + a[i - 1];}循环 (k = 0; k < q; k++){    lr = 控制台.读数字();    l = lr[0];    r = lr[1];    如果 (l == 1)    {        控制台.输出(a[r - 1]);    }    否则    {        控制台.输出(a[r - 1] - a[l - 2]);    }}