From 2970b8c41be9f7916501a686b7add26a01d31a99 Mon Sep 17 00:00:00 2001 From: ho94949 Date: Sat, 19 Aug 2023 20:07:34 +0900 Subject: [PATCH 1/3] EGZ modification --- _posts/2023-07-23-egz.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2023-07-23-egz.md b/_posts/2023-07-23-egz.md index 8f21bf03..3a5c4b9a 100644 --- a/_posts/2023-07-23-egz.md +++ b/_posts/2023-07-23-egz.md @@ -10,7 +10,7 @@ Erdös-Ginzburg-Ziv 정리는 임의의 길이 $2n-1$의 정수열에 대해 길 # Erdös-Ginzburg-Ziv 정리와 증명 -Erdös-Ginzburg-Ziv 정리는 길이가 $2n-1$인 임의의 정수열 $A = \{ {a}_1, {a}_2, \cdots, {a}_{2n-1}\}$에 대해 길이가 $n$이고 원소의 합이 $n$의 배수인 부분수열이 항상 존재한다는 정리입니다. $A$에 따른 $A$의 부분수열을 Erdös-Ginzburg-Ziv 정리의 해법이라고 부릅니다. Erdös-Ginzburg-Ziv가 간단한 증명을 제시했고, 이 증명을 재구성해서 작성해보면 다음과 같습니다. +Erdös-Ginzburg-Ziv 정리는 길이가 $2n-1$인 임의의 정수열 $A = \{ {a}\_1, {a}\_2, \cdots, {a}\_{2n-1}\}$에 대해 길이가 $n$이고 원소의 합이 $n$의 배수인 부분수열이 항상 존재한다는 정리입니다. $A$에 따른 $A$의 부분수열을 Erdös-Ginzburg-Ziv 정리의 해법이라고 부릅니다. Erdös-Ginzburg-Ziv가 간단한 증명을 제시했고, 이 증명을 재구성해서 작성해보면 다음과 같습니다. From 47dc2e6c7cf4b3136cfac12d001193ece6fb006d Mon Sep 17 00:00:00 2001 From: ho94949 Date: Sat, 19 Aug 2023 20:07:53 +0900 Subject: [PATCH 2/3] Author modify --- _authors/ho94949.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_authors/ho94949.md b/_authors/ho94949.md index 09525d9b..d5cdccd5 100644 --- a/_authors/ho94949.md +++ b/_authors/ho94949.md @@ -1,5 +1,5 @@ --- name: ho94949 -title: 강한필 +title: 강혜아 image: /assets/images/authors/ho94949.png --- \ No newline at end of file From fa1b0e06de2b5db06c5fb7531a26327c5bed6a71 Mon Sep 17 00:00:00 2001 From: ho94949 Date: Sat, 19 Aug 2023 21:17:38 +0900 Subject: [PATCH 3/3] Added RMQ --- _posts/2023-08-19-range-query.md | 141 +++++++++++++++++++++++++++++++ assets/images/HYEA/rmq/img1.png | Bin 0 -> 19680 bytes 2 files changed, 141 insertions(+) create mode 100644 _posts/2023-08-19-range-query.md create mode 100644 assets/images/HYEA/rmq/img1.png diff --git a/_posts/2023-08-19-range-query.md b/_posts/2023-08-19-range-query.md new file mode 100644 index 00000000..f3efe3b7 --- /dev/null +++ b/_posts/2023-08-19-range-query.md @@ -0,0 +1,141 @@ +--- +layout: post +title: "연산에 대한 O(n log n) / O(1) 구간 쿼리" +author: ho94949 +date: 2023-08-19 15:00 +tags: [range-query, data-structure] +--- + +프로그래밍을 하면서 많이 맞닥뜨리는 연산중 하나는 "구간 쿼리"입니다. 결합법칙을 만족하는 어떤 종류의 연산이든, $O(N \log N)$ 전처리로 쿼리당 $O(1)$ 시간에 구간에 대한 쿼리를 답할 수 있는 구조를 설명하려고 합니다. + +# 구간 쿼리 + +구간 쿼리는 다음과 같은 문제입니다. + +1. (전처리) 배열 $A = (A_0, A_1, \cdots, A_{N-1})$과 연산 $\circ$가 주어집니다. +2. (쿼리) $1 \le l \le r \le N$이 주어지면, $A_l \circ A_{l+1} \circ \cdots \circ A_r$을 계산해야합니다. + +여기서, 우리가 주목해볼 연산의 성질은 다음과 같습니다. + +- 결합법칙: 임의의 세 원소 $a, b, c$에 대해 $a \circ (b \circ c) = (a \circ b) \circ c$가 성립합니다. +- 교환법칙: 임의의 두 원소 $a, b$에 대해 $a \circ b = b \circ a$가 성립합니다. +- 멱등법칙: 임의의 원소 $a$에 대해 $a \circ a = a$가 성립합니다. +- 항등원의 존재: 임의의 원소 $a$에 대해 $a \circ e = e \circ a = a$ 를 만족하는 고정된 $e$가 존재합니다. +- 역원의 존재: 임의의 원소 $a$에 대해 $a \circ a^{-1} = a^{-1} \circ a = e$를 만족하는 $a^{-1}$가 존재합니다. + +이 법칙들, 항등원 혹은 역원의 존재 여부는 연산마다 다릅니다. + +- $+$는 결합법칙, 교환법칙이 성립하고 항등원, 역원이 존재합니다. +- $\times$는 결합법칙, 교환법칙이 성립하고 항등원이 존재합니다. +- $-$는 어떤 법칙도 성립하지 않고, 항등원도 존재하지 않습니다. +- 두 행렬의 곱셈은 결합법칙이 성립하고 항등원이 존재합니다. +- 최솟값, 최댓값 연산은 결합법칙, 교환법칙, 멱등법칙이 성립하며, 경우에 따라 항등원이 존재합니다. (주로 $+\infty$, $-\infty$로 표기합니다) +- $(L_1, R_1) \circ (L_2, R_2) = (L_1, R_2)$로 정의되는 연산이 있다고 합시다. 이 연산은 결합법칙, 멱등법칙이성립합니다. + +이렇게 연산의 종류에 따라 다양한 성질이 존재하고, 이 성질에 맞는 특징을 이용해서 문제를 해결하면 됩니다. + +- 결합법칙이 성립하고 역원이 존재하는 연산에 대해서는 $O(N)$ 전처리로 쿼리당 $O(1)$ 시간에 문제의 답을 할 수 있습니다. +- 결합법칙, 교환법칙, 멱등법칙이 성립하는 연산에 대해서는 $O(N \log N)$ 전처리로 쿼리당 $O(1)$ 시간에 문제의 답을 할 수 있습니다. + +첫 번째 방식은 "누적합", 두 번째 방식은 "희소 배열"이라는 이름으로 잘 알려져있습니다. 우리는 두 번째 방식에서 조건을 약화시킨, "결합법칙"이 성립하는 임의의 연산에 대해서 $O(N \log N)$ 전처리로 쿼리당 $O(1)$ 시간에 문제의 답을 하는 방법에 대해 알아볼 것입니다. + +# 아이디어 + +기본적인 아이디어는, $A_l \circ A_{l+1} \circ \cdots \circ A_m$과 $A_{m+1} \circ A_{m+2} \circ \cdots \circ A_r$을 알고 있으면, 둘을 연산하는 것으로 $A_l \circ A_{l+1} \circ \cdots \circ A_r$을 계산할 수 있다는 것입니다. 전처리 과정에서 적당한 구간을 연산한 것들을 가지고 있으면, 문제를 해결할 수 있습니다. 편하게, $A_i \circ A_{i+1} \circ \cdots \circ A_j$를 $[i, j+1)$로 표현합시다. + +우리가 쿼리당 정확히 한 번의 연산을 통해서 답을 도출해야한다고 하면 문제는 다음과 같이 바뀔 수 있습니다: + +- 모든 $0 \le l < r \le N$ 에 대해서 적당한 $m$이 존재해서 $[l, m)$과 $[m, r)$이 모두 존재하도록 하면 됩니다. + +가장 자연스러운 생각은 $m = \frac{0+N}{2}$로 잡는 것입니다. 이 이후, $[0, m); [1, m); \cdots; [m-1, m)$ 을 계산하고 $[m, m+1); [m, m+2); \cdots; [m, r)$을, 총 $N$개의 값을 계산합니다. 이는 반복문으로 쉽게 계산할 수 있습니다. 이제 $0 \le l \le m \le r \le N$을 만족하는 $[l, r)$에 대한 답을 내놓을 수 있습니다. + +이제 계산하지 못하는 값은, $0 \le l < r \le m-1$과 $m+1 \le l < r \le N$ 부분이 됩니다. 문제의 형태가 똑같기 때문에 이는 재귀적으로 전처리해줄 수 있습니다. 어떤 $[l, r)$이 들어오면 $l \le m \le r$을 만족하는 올바른 $m$을 찾을 수 있습니다. + +전처리에 드는 연산 횟수 및 시간복잡도는 $T(N) = 2T(N/2) + O(N)$ 으로 $T(N) = O(N \log N)$이 되며, 전처리는 한 번의 연산으로 찾을 수 있습니다. + +# 구현 + +구현을 좀 더 단순하게 해봅시다. 위와같이 구현할 경우, 전처리 과정에서 해당하는 $m$을 찾는 과정이 $O(\log N)$시간이 걸리므로 조금 더 세련된 방법을 생각해봅시다. 가장 쉬운 방법은 $N$을 임의의 길이로 늘려서 $2^k$꼴로 만드는 것입니다. 이 경우, 아래쪽에 재귀호출을 부르는 모든 배열의 길이도 $2$의 거듭제곱꼴이 됩니다. 이제 $[L, R)$구간이 나눠지는 형태를 살펴봅시다. + +- 처음에 $L = 0, R = 2^k$ 이고 구간의 길이 $R-L = 2^k$입니다. 여기서 주목할 점은, $L$과 $R$이 구간의 길이의 배수라는 점입니다. +- $L, R$이 $R-L = 2^i$의 배수라고 합시다. $m = \frac{L+R}{2}$가 되고, $L, m, R$모두 $m-L = R-m = 2^{i-1}$의 배수가 됩니다. + +즉, 구간이 나눠지면서 양쪽 끝 인덱스는 구간 길이에 해당하는 $2^i$의 배수 형태를 유지하게 됩니다. $[L, R)$ 구간은 $j = 0, \cdots, k; v = 0, \cdots, 2^{k-j}-1$에 대해서 $[v \times 2^j, (v+1) \times 2^j)$꼴이 됩니다. + +| ![](/assets/images/HYEA/rmq/img1.png) | +| :-----------------------------------: | +| $N=16$일 때 저장된 값 | + +이제 쿼리로 주어진 $[l, r)$에 대해 적당한 $m$을 찾아봅시다. 쿼리로 주어진 $[l, r)$에 대해서 구간의 양 끝점인 $l$과 $r-1$이 모두 속하는 가장 긴 구간 $[L, R)$을 찾으면, $L \le l < \frac{L+R}{2} < r \le R$이 됩니다. 이는 $L, \frac{L+R}{2}, R$이 연속된 $2^{j-1}$꼴의 배수라는 점에서 착안하여, $l$과 $r$이 달라지는 가장 큰 자리수 비트를 이용해서 구하면 됩니다. 이는 $l \oplus r$의 가장 큰 비트를 구하면 됩니다. + +## 구현체 + +아래는 구현체입니다. + +- `sp[i][j]`는 크기가 $2^i$인 구간에서 $j$번째 위치에 저장된 값을 의미합니다. 위 그림을 참고하면 좋습니다. +- C++20의 `bit_width`에 의존합니다. `bit_width(x)` 를 `32-__builtin_clz(x)`로 대체해도 똑같습니다. +- `Query` 함수는 $A_l \circ \cdots \circ A_{r-1}$을 계산합니다. + +```cpp +#include +#include +#include +using namespace std; + +template +class RMQ +{ +private: + int N; + vector> sp; + +public: + RMQ() : N(0){}; + explicit RMQ(const vector &V) : N(int(V.size())), sp(bit_width((unsigned)max(N - 1, 1)), vector(N)) + { + for (int i = 0; i < (int)sp.size(); ++i) + { + for (int j = 0; j < N; j++) + if (j & (1 << i)) + { + if ((j - 1) & (1 << i)) + sp[i][j] = op(sp[i][j - 1], V[j]); + else + sp[i][j] = V[j]; + } + for (int j = N - 1; j >= 0; --j) + if (!(j & (1 << i))) + { + if (j != N - 1 && !((j + 1) & (1 << i))) + sp[i][j] = op(V[j], sp[i][j + 1]); + else + sp[i][j] = V[j]; + } + } + } + + S Query(int L, int R) + { + assert(0 <= L && L < R && R <= N); + --R; + if (L == R) + return sp[0][L]; + int idx = bit_width((unsigned)(L ^ R)) - 1; + return op(sp[idx][L], sp[idx][R]); + } +}; +``` + +## 예시 문제 + +- 예시 문제: [JOI Open Contest 2014 6번](https://www.acmicpc.net/problem/21829) + +- 예시 코드 (위의 `RMQ` 구현체를 포함하고, 이와 같이 작성합니다) + +```cpp +#include "secret.h" + +RMQ rmq; +void Init(int N, int A[]) { rmq = RMQ(vector(A, A + N)); } +int Query(int L, int R) { return rmq.Query(L, R + 1); } +``` \ No newline at end of file diff --git a/assets/images/HYEA/rmq/img1.png b/assets/images/HYEA/rmq/img1.png new file mode 100644 index 0000000000000000000000000000000000000000..dc612048eb0788195f8dba79c0248fd4333308a5 GIT binary patch literal 19680 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 G`~Lv4kxlmi literal 0 HcmV?d00001