문제 링크
- http://icpc.me/20193
문제 출처
- 2020 KOI 고등부 3번
사용 알고리즘
- 세그먼트 트리
- 스위핑
시간복잡도
- $O(N \log N \log X)$
풀이
최소 길이를 구하는 문제이므로 파라메트릭 서치를 생각해볼 수 있습니다.
$decision(R) := $ 길이가 $R$인 정사각형으로 $K$가지의 색을 모두 덮을 수 있는가? 라는 결정 문제를 $O(\log X)$번 해결하는 것으로 문제의 답을 구할 수 있습니다. 결정 문제를 푸는 방법을 알아봅시다.
$[X, X+R]$ 구간을 왼쪽에서 오른쪽으로 움직이면서 스위핑을 합시다. 점 $(x_i, y_i, k_i)$는 $X = x_i-R$ 시점(구간의 오른쪽 끝과 만나는 시점)에 구간에 들어가고, $X = x_i+1$ 시점(구간의 왼쪽 끝보다 작아지는 시점)에 구간에서 빠져나옵니다.
만약 모든 점들의 색깔이 다르다면, Segment Tree + Lazy Propagation을 이용해 점 $(x_i, y_i, k_i)$가 구간에 들어갈 때 $[y_i, y_i + R]$을 1만큼 증가시키고, 구간에서 빠져나올 때 $[y_i, y_i + R]$을 1만큼 감소시키면서, 최댓값이 $K$인 순간이 있는지 확인해주면 됩니다. 그러나 이 문제에서는 서로 같은 색깔을 가진 점들이 존재할 수 있습니다. 이런 경우는 어떻게 처리해야 할까요?
위에서 설명한 알고리즘은 똑같은 색깔에 대해 중복해서 값을 증가/감소시키는 경우가 발생하기 때문에 문제가 됩니다. 중복해서 값을 증가/감소시키는 것을 피하는 방법을 찾으면 됩니다.
현재 구간에 들어간 점들의 $y$좌표를 색깔별로 구분하여 저장합시다.
점 $(x_i, y_i, k_i)$가 구간에 들어갈 때는 이미 구간에 있는 색깔이 $k_i$인 점들 중 ($y_i$ 이하이면서 가장 큰 점)/($y_i$ 이상이면서 가장 작은 점)의 위치를 찾아서 그 사이 구간만 1 증가시키면 됩니다.
마찬가지로, 점 $(x_i, y_i, k_i)$가 구간에서 빠져나올 때는 구간에 있는 색깔이 $k_i$이고 현재 제거하는 점이 아닌 점들 중 ($y_i$ 이하이면서 가장 큰 점)/($y_i$ 이상이면서 가장 작은 점)의 위치를 찾아서 그 사이 구간만 1 감소시키면 됩니다.
어떤 수 이하이면서 가장 큰 수 / 이상이면서 가장 작은 수는 std::multiset
을 이용해 $O(\log N)$만에 찾을 수 있습니다. 또한 Segment Tree + Lazy Propagation을 이용해 구간의 값을 증가시키는 것과 최댓값을 구하는 것도 $O(\log N)$만에 수행할 수 있습니다.
결정 문제마다 이 작업을 $2N$번씩 수행하고, 이러한 결정 문제를 총 $O(\log X)$번 풀기 때문에 전체 시간 복잡도는 $O(N \log N \log X)$가 됩니다.
전체 코드
1 |
|