본문으로 건너뛰기
김신건의 로그

누적 합 (Prefix Sum)

· 수정 · 📖 약 3분 · 809자/단어 #algorithm #foundation #prefix-sum
prefix sum, 누적 합, 구간 합, prefix-sum

정의

누적 합 (Prefix Sum) 은 배열 a[0..N-1] 에 대해 S[i] = a[0] + a[1] + ... + a[i-1] (또는 1-indexed S[i] = a[1] + ... + a[i]) 을 미리 계산해 두고, 임의 구간 합 a[l..r] 을 O(1) 에 구하는 정형.

sum(l, r) = S[r + 1] - S[l]

문제 풀이에서 “구간 N 개 × Q 개 쿼리” 가 O(N + Q) 로 떨어지는 가장 기본 패턴.

문제 상황과 동기

Σ a[l..r] 을 Q 번 묻는다.

  • naive: 매 쿼리마다 l..r 순회. O(N · Q). N=Q=10^5 면 10^10, 절대 안 됨.
  • prefix sum: O(N) 전처리 + O(1) 쿼리. 총 O(N + Q).

핵심 통찰: 합 함수 S(x) 를 한 번만 계산하면, 임의 구간은 두 점의 차. 누적은 도함수 / 미분이 가능한 모든 연산에 일반화 (XOR, AND/OR, min/max 같은 단조 연산은 누적 가능 / 불가능).

시각화

핵심 아이디어

invariant: S[i] = 처음 i 개 원소의 합. 두 누적 합의 가 구간 합.

S[0] = 0
S[i] = S[i-1] + a[i-1]   for i = 1..N

sum(l, r) (0-indexed, inclusive)
  = a[l] + a[l+1] + ... + a[r]
  = S[r+1] - S[l]

확장:

  • 2D prefix sum: S[i][j] = Σ_{i' ≤ i, j' ≤ j} a[i'][j']. 구간 사각형 합 O(1).
  • 차분 배열 (difference array): prefix sum 의 역. 구간 갱신 O(1) + 끝에 한번 누적.
  • mod prefix: mod 가 있을 때 음수 조심.
  • XOR prefix: 덧셈 대신 XOR. 구간 XOR 도 O(1).

알고리즘

build_prefix(a):
    S[0] = 0
    for i = 1..N:
        S[i] = S[i-1] + a[i-1]

range_sum(l, r):    # 0-indexed inclusive
    return S[r+1] - S[l]

구현

// 1D prefix sum, O(N) 전처리 + O(1) 쿼리
#include <bits/stdc++.h>
using namespace std;
int main() {
  int n, q; cin >> n >> q;
  vector<long long> a(n), S(n + 1, 0);
  for (auto& v : a) cin >> v;
  for (int i = 1; i <= n; i++) S[i] = S[i-1] + a[i-1];
  while (q--) {
      int l, r; cin >> l >> r;          // 1-indexed [l, r]
      cout << S[r] - S[l-1] << "\n";
  }
}
stdin
5 3
1 2 3 4 5
1 3
2 4
1 5
결과
6
9
15

복잡도

항목
전처리O(N) 시간, O(N) 공간
쿼리O(1) 시간
전체O(N + Q)
갱신 (한 점 변경)O(N) - prefix 재계산 필요 → [[Segtree

2D 누적 합

S[i][j] = a[i][j] + S[i-1][j] + S[i][j-1] - S[i-1][j-1]

rect_sum(r1, c1, r2, c2)
  = S[r2][c2] - S[r1-1][c2] - S[r2][c1-1] + S[r1-1][c1-1]

inclusion-exclusion 한 단계.

변형

연산prefix 가능?비고
+, XOR가환 + inverse 존재
min, maxinverse 없음 → [[Sparse Table
곱셈 (mod)✓ if mod inverse0 곱 주의
AND, ORinverse 없음
차분 배열 (역)-구간 +k 갱신 O(1), 끝에 prefix

함정

1. 1-indexed vs 0-indexed

sum(l, r) 에서 S[r] - S[l-1] (1-indexed) 와 S[r+1] - S[l] (0-indexed) 둘 다 자주 헷갈림. 한 표기 일관성 있게.

2. 합 오버플로우

C++ 에서 N=10^5 이상이면 합이 long long 범위 필요. int 누적은 위험.

3. 음수 mod

(S[r] - S[l-1]) % MOD 가 음수가 될 수 있다. + MOD 후 다시 mod.

4. 갱신 빈도

원소 갱신이 잦으면 prefix sum 은 매번 재계산 (O(N)) 비용. 그 경우 세그먼트 트리 또는 Fenwick.

BOJ 연습 문제

번호제목정답률링크
BOJ 11659구간 합 구하기 4-kokoa-lab
BOJ 11660구간 합 구하기 5 (2D)-kokoa-lab
BOJ 2018수들의 합 5-kokoa-lab
BOJ 16139인간-컴퓨터 상호작용-kokoa-lab

참고

이 글의 용어 (5개)
두 포인터 (Two Pointer)algorithm
정의 두 포인터 (Two Pointer) 는 정렬 또는 단조 구조 에서 두 인덱스 , 을 서로 다른 속도 / 방향 으로 이동시키며 부분 구간 / 페어를 O(N) 에 탐색하는 기법…
세그먼트 트리 (Segment Tree)algorithm
정의 세그먼트 트리 (Segment Tree) 는 배열의 구간 쿼리 (range query) 와 점 갱신 (point update) 를 모두 O(log N) 에 처리하는 이진 트…
슬라이딩 윈도우 (Sliding Window)algorithm
정의 슬라이딩 윈도우 (Sliding Window) 는 배열/문자열 위에서 고정 크기 또는 가변 크기 윈도우가 한 방향으로 미끄러지며 각 윈도우마다 조건 (합, 최댓값, 중복 여…
차분 배열 (Difference Array)algorithm
정의 차분 배열 (Difference Array) 은 배열 의 인접 차 (adjacent difference) 를 저장하는 배열 (단, ). 원 배열은 , 즉 d 의 누적 합 (…
희소 배열 (Sparse Table)algorithm
정의 희소 배열 (Sparse Table) 은 정적 배열에서 결합 법칙을 만족하는 idempotent 연산 (min, max, gcd, lcm 등) 의 구간 쿼리를 O(1) 시간…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기