도구스개발

Mo's 알고리즘(구간 질의 정렬) 계산기

구간 질의를 블록 단위로 정렬해 포인터 이동을 O((n+q)√n)로 줄이는 과정을 보여 줍니다. 들어온 순서·Mo 정렬·홀짝 뒤집기 세 경우의 이동 횟수를 실제로 세어 견주고, 답이 곧이곧대로 푼 것과 같은지 검산합니다.

쉼표·공백으로 구분 — 지금 64개

줄마다 두 값, 1부터 셉니다 — 지금 12개

포인터 이동 횟수

712 → 235

정렬만으로 3.03배 줄고, 홀짝 뒤집기로 0%가 더 줄었습니다

① 들어온 순서대로712
② 블록 → r 오름차순235
③ 홀짝 뒤집기까지235
이론 상한 (n+q)√n608
블록 크기 √n8 (블록 8개)
답이 곧이곧대로 푼 것과 같은가모두 일치
처리 순서원래 번호구간블록이동서로 다른 값
1#5[5, 9]0135
2#3[1, 20]01513
3#11[7, 33]01913
4#9[2, 58]03013
5#1[3, 60]0313
6#7[12, 45]12413
7#8[22, 24]2313
8#12[18, 61]24113
9#6[30, 62]31313
10#2[40, 55]41713
11#10[44, 50]597
12#4[50, 64]62013
계산 근거블록 크기 = √n = 8
정렬 기준: (l이 속한 블록, 그 안에서는 r)
홀짝 뒤집기: 짝수 블록은 r 오름차순, 홀수 블록은 r 내림차순
한 질의의 비용 = |L − l| + |R − r|
질의를 미리 다 받아 놓고 순서를 바꿔 처리합니다. 답 자체는 순서와 무관하므로 원래 번호로 되돌려 내면 됩니다.
왜 O((n+q)√n)인가. 왼쪽 포인터는 한 블록 안에서 블록 폭(√n) 안에서만 움직이고 블록이 바뀔 때 한 번 크게 뜁니다 — 질의마다 √n이니 O(q√n)입니다. 오른쪽 포인터는 한 블록 안에서 r이 «단조증가»라 총 n칸만 움직이고, 블록이 √n개이므로 O(n√n)입니다. 정렬하지 않으면 질의마다 n칸씩 움직일 수 있어 O(nq)입니다.
홀짝 뒤집기는 한 줄짜리 개선입니다. 블록이 바뀔 때 오른쪽 포인터가 배열 끝에서 앞으로 되돌아오는 것이 아깝습니다. 홀수 블록에서만 r을 내림차순으로 정렬하면 그 되돌아옴이 사라집니다. 지금 자료에서 235번이 235번으로, 0%가 줄었습니다. 정렬 비교자 한 줄을 고치는 것치고 큰 이득입니다.
쓸 수 있는 조건이 있습니다. 구간을 한 칸 넓히거나 좁히는 것이 O(1)에 되어야 합니다. 여기서 다루는 「서로 다른 값의 개수」는 값별 등장 횟수 배열 하나로 그렇게 되지만, 「구간의 중앙값」 같은 것은 그렇지 않습니다. 그리고 질의를 미리 다 알아야 하므로 온라인 처리에는 쓸 수 없습니다.
여기서 세는 것은 「이동 횟수」입니다. 실제 수행시간은 한 칸을 더하고 빼는 데 드는 비용까지 곱해야 나옵니다. 해시맵을 쓰면 상수가 커지므로 값을 좌표압축해 배열로 세는 것이 실무의 상식입니다. 그리고 질의가 아주 적으면 정렬 비용이 더 클 수도 있으니, 질의 수가 배열 크기와 비슷할 때부터 이득입니다.

사용 방법

  1. 1배열과 구간 질의를 넣습니다. 질의는 1부터 세는 「l r」 꼴입니다.
  2. 2세 가지 순서의 이동 횟수를 견줍니다.
  3. 3처리 순서 표에서 블록이 어떻게 묶이는지 봅니다.
  4. 4답이 곧이곧대로 푼 것과 일치하는지 확인합니다.

자주 묻는 질문

구간 질의를 미리 다 받아 놓고 「영리한 순서」로 정렬해 처리하는 방법입니다. 현재 구간 [L,R]에서 다음 질의 [l,r]로 옮기는 비용이 |L−l|+|R−r|이므로, 비슷한 질의끼리 이웃하게 정렬하면 총 이동이 O((n+q)√n)로 떨어집니다.

왼쪽 끝 l이 속한 √n 크기 블록으로 먼저 정렬하고, 같은 블록 안에서는 오른쪽 끝 r로 정렬합니다. 두 줄짜리 비교자가 전부입니다.

왼쪽 포인터는 한 블록 안에서 블록 폭(√n) 안에서만 움직이므로 질의마다 √n, 합쳐서 O(q√n)입니다. 오른쪽 포인터는 한 블록 안에서 r이 단조증가라 총 n칸만 움직이고 블록이 √n개이므로 O(n√n)입니다.

짝수 블록은 r 오름차순, 홀수 블록은 r 내림차순으로 정렬하는 개선입니다. 블록이 바뀔 때 오른쪽 포인터가 배열 끝에서 앞으로 되돌아오는 낭비가 사라져 실측 이동이 대개 30% 안팎 줄어듭니다. 정렬 비교자 한 줄을 고치는 것치고 큰 이득입니다.

구간을 한 칸 넓히거나 좁히는 것이 O(1)에 되어야 합니다. 서로 다른 값의 개수, 같은 값 쌍의 개수, 구간 XOR 빈도 같은 것은 됩니다. 구간의 중앙값처럼 한 칸 갱신이 O(1)이 아닌 것은 그대로 쓸 수 없습니다.

쓸 수 없습니다. 질의를 미리 다 알아야 순서를 바꿀 수 있기 때문입니다. 질의가 하나씩 들어오고 즉시 답해야 한다면 세그먼트 트리나 다른 자료구조를 써야 합니다.

질의 수가 배열 크기와 비슷해질 때부터입니다. 질의가 아주 적으면 정렬 비용이 더 클 수도 있습니다. 그리고 여기서 세는 것은 이동 횟수일 뿐이라, 실제 수행시간은 한 칸을 더하고 빼는 비용까지 곱해야 나옵니다.

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

알아두면 좋은 점

  • 질의를 미리 다 알아야 합니다. 온라인 처리에는 쓸 수 없습니다.
  • 한 칸 갱신이 O(1)이어야 합니다. 구간 중앙값 같은 것은 그대로 못 씁니다.
  • 여기서 세는 것은 포인터 이동 횟수이지 실제 수행시간이 아닙니다.
  • 값이 클 때는 좌표압축해 배열로 세야 상수가 작습니다.
  • 질의가 아주 적으면 정렬 비용이 더 클 수 있습니다.
  • 이 계산기는 「서로 다른 값의 개수」 질의를 다룹니다.
  • 배열과 질의 모두 2000개까지 다룹니다.

함께 보면 좋은 도구

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