Introduction
Sqrt Decomposition이란 구간을 $\sqrt{n}$개의 bucket으로 나눠 쿼리를 $O(\sqrt{n})$ 만에 처리하는 테크닉이다.
물론 세그먼트 트리를 이용하면 $O(\log{n}) $만에 구간 쿼리를 계산할 수 있지만, Sqrt Decomposition 은 Mo's Algorithm에 기반이 된다고 하니 배워보자.
코드
아래의 코드는 이 문제를 기준으로 작성되었다.
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
const int MAX = 1000000001, MIN = 0;
struct Ele {
int min, max;
};
int n, m, sqr;
Ele arr[100001], bucket[400];
inline Ele Calculate(Ele e1, Ele e2) {
return { min(e1.min, e2.min), max(e1.max, e2.max) };
}
void Init(void) {
sqr = ceil(sqrt(n));
for (int i = 0; i < sqr; i++)
bucket[i] = { MAX, MIN };
for (int i = 0; i < n; i++)
bucket[i / sqr] = Calculate(bucket[i / sqr], arr[i]);
return;
}
void Update(int idx, int val) {
arr[idx] = { val, val };
bucket[idx / sqr] = { MAX, MIN };
for (int i = 0; i < sqr; i++)
bucket[idx / sqr] = Calculate(bucket[idx / sqr], arr[(idx / sqr) * sqr + i]);
return;
}
Ele Query(int ts, int te) {
Ele ans = { MAX, MIN };
for (int i = 0; i < sqr; i++) {
int s = i * sqr, e = i * sqr + sqr - 1;
if (e < ts || te < s)
continue;
else if (ts <= s && e <= te)
ans = Calculate(ans, bucket[i]);
else {
for (int j = max(s, ts); j <= min(e, te); j++)
ans = Calculate(ans, arr[j]);
}
}
return ans;
}
int main(void) {
scanf("%d %d", &n, &m);
for (int i = 0; i < n; i++) {
int x;
scanf("%d", &x);
arr[i] = { x, x };
}
Init();
for (int i = 0; i < m; i++) {
int s, e;
scanf("%d %d", &s, &e);
Ele a = Query(s - 1, e - 1);
printf("%d %d\n", a.min, a.max);
}
return 0;
}
함수 설명
Calculate : 요소에 대한 연산으로 이 함수를 수정함으로써 구간 합을 처리하는등 으로 바꿀 수 있다.
Init : 모든 bucket을 $O(n)$ 만에 초기화 한다.
Update : 한 요소의 값을 업데이트 하는 함수로, $O(\sqrt{n})$ 만큼 걸린다.
Query : 하나의 쿼리를 처리하는 함수로, $O(\sqrt{n})$ 만큼 걸린다.
'PS' 카테고리의 다른 글
백준 9212 (트라이앵글) (0) | 2024.01.10 |
---|---|
Mo's Algorithm (0) | 2023.08.14 |
Master Theore (0) | 2023.08.11 |
단절점 (0) | 2023.08.11 |
Euler tour technique (0) | 2023.08.08 |