June

머지 소트 트리

머지 소트 트리

머지 소트 트리는 세그먼트 트리의 한 변형으로, 각 노드가 그 구간에 포함된 원소들을 정렬된 상태로 저장하고있는 자료구조이다.

각 리프 노드는 배열의 한 원소이고, 내부의 노드들은 해당 구간의 원소들을 정렬된 배열로 병합 저장해 놓은 형태이다. 그림으로 나타내면 아래와 같다.

mermaid
graph TB
    A["[1, 2, 3, 4, 5] "] 
    B["[1, 5] "] 
    C["[2, 3, 4] "] 
    D["[5]"] 
    E["[1] "] 
    F["[2, 4] "] 
    G["[3] "] 
    H["[4] "] 
    I["[2] "]

    A --> B
    A --> C
    B --> D
    B --> E
    C --> F
    C --> G
    F --> H
    F --> I

시간 복잡도

  • 트리 구성:

    각 레벨마다 병합 정렬처럼 O(nlogn)이 소요

    ⇒ 전체 구성 시간 O(n log n)

  • 쿼리 처리 (예: 구간 [l, r]에서 x보다 큰 수의 개수)
    • 세그먼트 트리처럼 O(log n)개의 노드를 방문
    • 각 노드에서 이진 탐색으로 개수 구하기 → O(log n)

      ⇒ 전체 쿼리 시간 O(log² n)

사용 예시

머지 소트 트리는 구간 내 조건에 맞는 원소 개수를 빠르게 구할 때 유용하다.

예시 문제 유형:

  • 구간 [l, r]에서 k번째로 작은 수 찾기
  • 구간 [l, r]에서 x 보다 큰 원소의 개수
  • 구간 [l, r]에서 x 이상인 원소의 합 (변형 필요)

예시 코드

c++
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;
int n, m, k;
vector<long long> num;
vector<vector<long long>> segTree; // 각 노드에 "정렬된 구간 원소" 저장

// 트리 빌드
void build(int node, int start, int end) {
    if (start == end) {
        segTree[node] = { num[start] };
    } else {
        int mid = (start + end) / 2;
        build(node * 2, start, mid);
        build(node * 2 + 1, mid + 1, end);
        segTree[node].resize(segTree[node*2].size() + segTree[node*2+1].size());
        merge(segTree[node*2].begin(), segTree[node*2].end(),
              segTree[node*2+1].begin(), segTree[node*2+1].end(),
              segTree[node].begin());
    }
}

// 구간 [left, right]에서 val보다 큰 원소 개수
int query(int node, int start, int end, int left, int right, long long val) {
    if (left > end || right < start) return 0;
    if (left <= start && end <= right) {
        return segTree[node].end() - upper_bound(segTree[node].begin(), segTree[node].end(), val);
    }
    int mid = (start + end) / 2;
    return query(node*2, start, mid, left, right, val) +
           query(node*2+1, mid+1, end, left, right, val);
}

void input() {
    cin >> n >> m >> k;
    num.resize(n);
    for (int i = 0; i < n; i++) {
        cin >> num[i];
    }
}

void solve() {
    segTree.assign(4 * n, {});
    build(1, 0, n - 1);
    for (int i = 0; i < m + k; i++) {
        int first;
        long long x, y;
        cin >> first;
        if (first == 1) {
            // 머지 소트 트리 업데이트는 비효율적 (O(log² N)) → 보통 안 함
            // 구현 가능하지만 여기서는 생략
        } else if (first == 2) {
            cin >> x >> y;
            cout << query(1, 0, n - 1, x - 1, y - 1, 5) << "\n"; // 예: 5보다 큰 수 개수
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    input();
    solve();
}

Seoul, South Korea

jwsong5160@gmail.com

© 2026 Junwoo Song