도구스개발

평방 분할(구간 질의) 계산기

배열을 √n 크기 버킷으로 나눠 구간 합·최솟값·최댓값을 O(√n)에 답합니다. 버킷 크기를 바꿔 가며 실제 연산 횟수를 재어 「왜 하필 √n인가」가 U자 곡선으로 보이게 했습니다.

공백이나 쉼표로 구분합니다. 60개까지 봅니다.

이 배열의 최적은 √(n/2) ≈ 3칸입니다.

번째
번째

3~15번째의 합

67

원소 5개 + 버킷 2개 = 7번 봤습니다. 곧이곧대로 훑으면 13번입니다.

배열 길이 n20칸
버킷 크기 · 개수4칸 · 5개
왼쪽 자투리3~4번째
통째로 쓴 버킷2개
오른쪽 자투리13~15번째
연산 횟수7번
전수 풀이와 대조67 — 일치합니다

버킷과 요약값

버킷범위이번 질의
01~44 7 2 922하나씩 봄
15~81 8 3 618요약값만 읽음
29~125 10 2 724요약값만 읽음
313~164 9 1 620하나씩 봄
417~208 3 5 218건드리지 않음

가운데 버킷은 요약값 한 번만 읽고 넘어갑니다. 양 끝의 잘린 버킷만 원소를 하나씩 보므로, 최악에도 자투리 2b개 + 버킷 n/b개면 끝납니다.

버킷 크기를 바꿔 가며 실제로 재어 본 연산 횟수

버킷 크기버킷 수평균 연산최악이론 2b + n/b
1207.332022
2105.051214
374.761012.67
4 (지금)55.051113
545.431214
645.621315.33
736.131416.86
836.271618.5
936.651820.22
1027.332022
1127.332023.82
1227.332025.67
1327.332027.54
1427.332029.43
1527.332031.33
1627.332033.25
1727.332035.18
1827.332037.11
1927.332039.05
2017.332041

모든 (시작, 끝) 쌍을 실제로 물어보고 센 값입니다. 가장 적은 곳이 b = 3이고 이론 최적 √(n/2) ≈ 3과 가깝습니다. 양 끝으로 갈수록 나빠지는 U자가 「왜 하필 √n인가」의 답입니다.

왜 하필 √n인가. 질의 하나의 비용이 대략 2b + n/b입니다 — 양 끝 자투리에서 최대 2b개, 가운데 버킷에서 최대 n/b개를 봅니다. 이것을 b로 미분해 0으로 두면 b = √(n/2)이고, 그때 비용이 2√(2n)이라 O(√n)이 됩니다. b가 작으면 버킷이 많아지고 크면 자투리가 길어져 양쪽 다 손해라 U자 곡선이 나옵니다.
세그먼트 트리가 더 빠른데 왜 이것을 쓰나요. O(log n)인 세그먼트 트리·펜윅 트리가 분명 빠릅니다. 그래도 평방 분할이 쓰이는 이유가 둘 있습니다. 구현이 훨씬 짧아 배열 하나면 끝나고 재귀도 없다는 것, 그리고 합치기 어려운 연산에도 붙는다는 것입니다. 세그먼트 트리는 두 구간의 답을 합쳐 큰 구간의 답을 만들 수 있어야 하는데, 최빈값이나 「서로 다른 값의 개수」는 그것이 안 됩니다. 평방 분할은 버킷마다 통계를 통째로 들고 있으면 됩니다.
최솟값 버킷은 O(1)로 고칠 수 없습니다. 합은 되돌릴 수 있어 「빼고 더하기」로 끝나지만, 최솟값은 지운 값이 그 버킷의 최솟값이었으면 다음 최솟값이 무엇인지 알 길이 없어 버킷을 다시 훑어야 합니다(O(b)). 더 작은 값으로 바꾸는 경우에만 O(1)입니다. 이 차이를 모르고 최솟값도 O(1)로 고치려다 틀리는 것이 단골 실수입니다.
한 버킷 안에서 끝나는 질의는 그냥 훑습니다. 시작과 끝이 같은 버킷에 있으면 요약값을 쓸 수가 없어 원소를 하나씩 봅니다. 이때 비용이 최대 b라 전체 최악값에 영향을 주지 않지만, 구현에서 이 경우를 빠뜨리면 왼쪽 자투리와 오른쪽 자투리가 겹쳐 같은 원소를 두 번 세게 됩니다.

사용 방법

  1. 1배열을 공백이나 쉼표로 구분해 넣고 구간 연산(합·최솟값·최댓값)을 고릅니다.
  2. 2버킷 크기를 정하고 질의 구간을 넣으면 답과 연산 횟수가 나옵니다.
  3. 3버킷 표에서 어느 버킷이 요약값만 읽히고 어느 버킷이 하나씩 읽히는지 봅니다.
  4. 4아래 표에서 버킷 크기를 바꿔 가며 잰 평균 연산 횟수가 U자를 그리는 것을 확인합니다.
  5. 5가장 적은 곳이 √(n/2) 근처에 오는 것을 봅니다.

자주 묻는 질문

배열을 크기 b짜리 버킷으로 잘라 버킷마다 요약값(합·최솟값 등)을 미리 구해 두는 방법입니다. 구간 질의가 「왼쪽 자투리 + 통째로 들어가는 버킷들 + 오른쪽 자투리」로 나뉘어, 자투리는 최대 2b개를 하나씩 보고 가운데는 버킷 요약값 최대 n/b개만 읽습니다.

질의 비용이 대략 2b + n/b인데, 이것을 b로 미분해 0으로 두면 b = √(n/2)가 나오기 때문입니다. 그때 비용이 2√(2n)이라 O(√n)이 됩니다. b가 작으면 버킷 개수가 많아지고 크면 자투리가 길어져 양쪽으로 다 손해라, 연산 횟수가 U자 곡선을 그립니다.

구현이 훨씬 짧고, 합치기 어려운 연산에도 붙기 때문입니다. 세그먼트 트리는 두 구간의 답을 합쳐 큰 구간의 답을 만들 수 있어야 하는데 최빈값이나 「서로 다른 값의 개수」는 그것이 안 됩니다. 평방 분할은 버킷마다 통계를 통째로 들고 있으면 되므로 그런 연산도 다룰 수 있습니다.

연산에 따라 다릅니다. 합처럼 되돌릴 수 있으면 원소를 고치고 버킷 요약값에서 옛 값을 빼고 새 값을 더하면 되어 O(1)입니다. 최솟값·최댓값은 지운 값이 그 버킷의 최솟값이었으면 다음 최솟값을 알 길이 없어 버킷을 다시 훑어야 하므로 O(b)입니다.

됩니다. 이 점이 차분 배열과 다릅니다. 차분 배열은 갱신을 전부 받고 마지막에 한 번 읽는 경우에만 이기지만, 평방 분할은 버킷 요약값을 그때그때 고칠 수 있어 질의와 갱신이 섞여 들어와도 각각 O(√n) 안팎으로 처리합니다.

요약값을 쓸 수 없어 원소를 하나씩 봅니다. 이때 비용이 최대 b라 전체 최악값에는 영향을 주지 않지만, 구현에서 이 경우를 따로 처리하지 않으면 왼쪽 자투리와 오른쪽 자투리가 겹쳐 같은 원소를 두 번 세게 됩니다. 이 도구는 그 경우를 나눠 처리합니다.

경진 프로그래밍에서 구간 질의를 빠르게 짜야 할 때, 특히 세그먼트 트리로 표현하기 어려운 연산일 때 씁니다. Mo's 알고리즘처럼 질의를 미리 다 받아 정렬하는 기법도 같은 √n 발상 위에 서 있고, 데이터베이스의 블록 단위 통계(존 맵)도 본질적으로 같은 구조입니다.

전송되지 않습니다. 계산은 모두 브라우저 안에서 이루어지고 넣은 값은 이 기기에만 남습니다.

알아두면 좋은 점

  • 연산 횟수 곡선은 모든 (시작, 끝) 쌍을 실제로 물어보고 센 값입니다. 이론 어림과 나란히 놓았습니다.
  • 실측 최소는 평균 기준이라 이론 최적(최악 기준) √(n/2)보다 조금 크게 나올 수 있습니다.
  • 표를 보이기 위해 배열은 60개까지만 받습니다. 알고리즘 자체는 크기 제한이 없습니다.
  • 결과가 정말 맞는지 확인하려고 곧이곧대로 훑은 값을 함께 냅니다.

함께 보면 좋은 도구

마지막 검증: 2026년 9월 2일 · 결과는 참고용 추정치입니다.