ν¬μ†Œ λ°°μ—΄(Sparse Table)

λ°°μ—΄ μ›μ†Œμ˜ κ°œμˆ˜κ°€ 무쑰건 λ°°μ—΄μ˜ length 값보닀 μž‘μ€ λ°°μ—΄

데이터가 μ €μž₯λ˜μ§€ μ•Šμ€ κ²½μš°κ°€ 더 λ§Žμ€ ν¬μ†Œ ν–‰λ ¬κ³Ό 같이, ν¬μ†Œ 배열은 λ°°μ—΄μ˜ μ›μ†Œ μœ„μΉ˜κ°€ 연속적이지 μ•Šμ€ 배열을 말함

μ΄λŸ¬ν•œ ν¬μ†Œλ°°μ—΄μ˜ νŠΉμ§•μ„ μ΄μš©ν•΄ κ·Έλž˜ν”„μ˜ 사이클을 νƒμƒ‰ν•΄λ‚˜κ°€λŠ” 문제λ₯Ό ν’€ 수 μžˆλ‹€.

ν¬μ†Œ λ°°μ—΄ μ•Œκ³ λ¦¬μ¦˜

κ·Έλž˜ν”„

λ‹€μŒκ³Ό 같이 사이클이 μžˆλŠ” κ·Έλž˜ν”„κ°€ μ‘΄μž¬ν•˜κ³ , νŠΉμ • 정점(v)μ—μ„œ μ‹œμž‘ν•΄ n개의 간선을 이동해 도착할 수 μžˆλŠ” 정점을 κ΅¬ν•œλ‹€κ³  μƒκ°ν•΄λ³΄μž.

μΌλ°˜μ μœΌλ‘œλŠ” κ°„μ„  1개λ₯Ό nλ²ˆμ”© μ΄λ™ν•˜μ—¬ λ„μ°©ν•˜λŠ” 정점을 μ°ΎλŠ” 방법을 λ– μ˜¬λ¦΄ 것이닀.

ν•˜μ§€λ§Œ μœ„μ˜ 문제λ₯Ό 반볡적으둜 ν’€μ–΄μ•Ό ν•œλ‹€λ©΄? λͺ¨λ“  v정점에 λŒ€ν•΄ n개의 κ°„μ„ λ§ŒνΌμ”© μ΄λ™ν•œλ‹€λ©΄ μˆ˜μ—†μ΄ 많이 이동해야 ν•œλ‹€. κ²Œλ‹€κ°€ μœ„ κ·Έλž˜ν”„λŠ” 사이클이 μ‘΄μž¬ν•˜κΈ°λ•Œλ¬Έμ—, μ–΄λŠ μˆœκ°„λΆ€ν„°λŠ” 같은 이동을 λ°˜λ³΅ν•˜κ²Œλ  것이닀.

이 문제λ₯Ό ν¬μ†Œ λ°°μ—΄λ‘œ ν•΄κ²°ν•΄λ³΄μž.

λ§Œμ•½ 1번 μ •μ μ—μ„œ μ‹œμž‘ν•΄ 7개의 간선을 이동해 도착할 수 μžˆλŠ” 정점을 κ΅¬ν•œλ‹€λ©΄ 이동 νšŸμˆ˜λŠ” λ‹€μŒκ³Ό 같을 것이닀.

7 = 4 + 2 + 1

7개의 간선을 μ΄λ™ν•œλ‹€κ³  ν•΄μ„œ 1번 μ΄λ™ν•˜λŠ” 간선을 7개 κ±°μ³κ°€λŠ” 것이 μ•„λ‹ˆλ‹€.

1λ²ˆμ—μ„œ 4번 μ΄λ™ν•˜μ—¬ 5λ²ˆμ— 도착, 5λ²ˆμ—μ„œ 2번 μ΄λ™ν•˜μ—¬ 4λ²ˆμ— 도착, λ§ˆμ§€λ§‰μœΌλ‘œ 4λ²ˆμ—μ„œ 1번 μ΄λ™ν•˜μ—¬ 2번으둜 λ„μ°©ν•œλ‹€λ©΄ 이동 νšŸμˆ˜λŠ” 7λ²ˆμ—μ„œ 3번으둜 μ€„μ–΄λ“€κ²Œ λœλ‹€.

이처럼 간선을 1κ°œμ”© μ΄λ™ν•˜μ§€ 말고, 1개, 2개, 4개, 8개, … 와같이 1λΆ€ν„° log nκ°œκΉŒμ§€ ν•œλ²ˆμ— μ΄λ™ν•˜κ³ , μ΄λ ‡κ²Œ λ„λ‹¬ν•œ 정점을 배열에 μ €μž₯ν•œλ‹€λ©΄ λͺ‡ 개의 간선도 λΉ λ₯΄κ²Œ 이동할 수 μžˆλ‹€.

ν¬μ†Œλ°°μ—΄

이동 횟수 1 2 3 4 5 6 7 8 9
1번 이동 4 3 5 2 1 5 3 6 6
2번 이동 2 5 1 3 4 1 5 5 5
4번 이동 5 4 2 1 3 2 4 4 4

μœ„ ν…Œμ΄λΈ”μ€ 사이클이 μ‘΄μž¬ν•˜λŠ” κ·Έλž˜ν”„μ˜ 이동 λ…Έλ“œλ₯Ό ν‘œν˜„ν•œ κ²ƒμ΄λ―€λ‘œ, 각 ν–‰μ˜ μ›μ†Œ κ°œμˆ˜κ°€ μ—΄μ˜ κ°œμˆ˜λ³΄λ‹€ μž‘μ€ ν¬μ†Œ λ°°μ—΄λ‘œ ν‘œν˜„λ˜λŠ” 것을 μ•Œ 수 μžˆλ‹€.

이런 νŠΉμ„±μ„ μ΄μš©ν•΄ 1 ~ log n κΉŒμ§€ μ΄λ™ν•˜μ—¬ λ„μ°©ν•˜λŠ” 정점을 ν¬μ†Œ 배열에 μ €μž₯ν•΄λ‘ μœΌλ‘œμ¨ 사이클이 μ‘΄μž¬ν•˜λŠ” κ·Έλž˜ν”„μ—μ„œμ˜ κ°„μ„  이동을 λΉ λ₯΄κ³  μ‰½κ²Œ ν•΄κ²°ν•  수 μžˆλ‹€.

ν¬μ†Œ λ°°μ—΄ μ•Œκ³ λ¦¬μ¦˜ κ΅¬ν˜„

// ν¬μ†Œ λ°°μ—΄
static int[][] sparseTable = new int[logn+1][n+1];   // 1차원 λ°°μ—΄ κΈΈμ΄λŠ” 이동 횟수λ₯Ό, 2차원 λ°°μ—΄ κΈΈμ΄λŠ” 총 μ •μ μ˜ 길이λ₯Ό 의미

// ν¬μ†Œ λ°°μ—΄ μƒμ„±ν•˜μ—¬ 각 μ •μ μ˜ 이동 νšŸμˆ˜λ³„ 도착 정점 기둝
public static void makeSparseTable() {
    // 1번 μ΄λ™ν•΄μ„œ λ„μ°©ν•˜λŠ” 정점
    for (int i=1; i<=n; i++) {
        sparseTable[0][i] = arr[i];
    }

    // log nλ²ˆκΉŒμ§€ μ΄λ™ν•΄μ„œ λ„μ°©ν•˜λŠ” 정점
    for (int k=1; k<logn+1; k++) {
        for (int i=1; i<=n; i++) {
            int next = sparseTable[k-1][i];
            sparseTable[k][i] = sparseTable[k-1][next];
        }
    }
}

// v μ •μ μ—μ„œ μΆœλ°œν•˜μ—¬ n개의 간선을 μ΄λ™ν•˜μ—¬ λ„μ°©ν•œ 정점 μ°ΎκΈ°
public static int query(int n, int v) {
    for (bit=size-1; bit>=0; bit--) {
        if ((n & (1<<bit)) != 0) {
            v = sparseTable[bit][v];
        }
    }
}


References

BOJ 17435 ν•©μ„±ν•¨μˆ˜μ™€ 쿼리 Sparse Table - λ‚¨λ‚¨μ„œμ˜ λΈ”λ‘œκ·Έ