문제 링크
- http://icpc.me/14460
문제 출처
- 2017 Feb USACO 3번
사용 알고리즘
- 분할 정복
- 세그먼트 트리
시간복잡도
- $O(N \log^2 N)$
풀이
$i$번째 소의 왼쪽 목초지 자리를 $A_i$, 오른쪽 목초지의 자리를 $B_i$라고 합시다. 두 소 $i, j$가 교차하면 $A_i < A_j$ 일 때 $B_i > B_j$입니다.
즉, $(A_i, B_i)$를 좌표 평면 위에 플로팅했을 때 자신보다 오른쪽 아래에 있는 점들 중, $|i - j| \leq K$인 개수를 구해서 더하면 됩니다.
2D Segment Tree를 쓰면 쉽게 풀리지만, Dynamic 2D Segment Tree를 구현하는 건 귀찮으므로 분할 정복을 합시다.
$[s, e]$ 구간의 중간 $m = \lfloor \frac{s + e}{2} \rfloor$를 잡읍시다.
$[s, m]$과 $[m+1, e]$ 구간 내부에서 발생하는 교차 횟수는 재귀적으로 처리하면 되므로, 두 구간 사이에서 발생하는 교차 횟수만 셀 것입니다.
먼저, $[s, m]$ 구간에 있는 원소와 $[m+1, e]$ 구간에 있는 원소들을 각각 y좌표 기준으로 정렬을 합시다.
구간의 합을 관리하는 Segment Tree를 만든 뒤, $[s, m]$, $[m+1, e]$ 구간의 원소들을 merge sort 하듯이 훑어주면서
- $[m+1, e]$ 구간에 속하는 원소의 경우에는 세그먼트 트리에서 현재 원소의 “인덱스” 위치에 1을 증가시키고
- $[s, m]$ 구간에 속하는 원소의 경우에는 세그먼트 트리에서 $[1, i-k-1]$, $[i+k+1, N]$ 범위에 쿼리를 날려서 정답을 구해주면 됩니다.
자세한 구현은 코드를 참고해주세요.
전체 코드
1 |
|