티스토리 뷰
문제
문제 풀이
순열 \(a[ \ ] = \{1, 2, ..., n\} \ (1 \le n \le 200000)\) 에 대하여 특정 위치 \(l_i\) 과 \(r_i\) 의 값을 바꾸는 연산이 \(q \ (1 \le q \le 50000)\) 번 수행될 때, 매 연산 후 순열에 존재하는 역접(inversion)의 수를 세는 문제다.
역접의 수는 크기가 \(a[x] > a[y] \ (x < y)\)인 쌍 \((x, y)\)의 수를 세는 것이므로, 간단하게 모든 원소에 대해서 자신보다 앞에 있으면서 큰 원소의 개수를 일일히 다 세서 구할 수 있다. 하지만 전체 시간복잡도 \(O(q \times n^2)\)가 예상되므로 문제를 주어진 제한시간내에 해결하기에는 크게 역부족인 방법이다.
매 연산 후, 역접의 수가 어떻게 변하는지를 관찰하면 보다 효율적인 방법이 나온다. 현재 순열의 상태가 다음과 같다고 하자.
현재 순열에서 역접의 수는 7이다. 이때, 다음 연산으로 4와 7의 위치가 변경된 후 역접의 수가 어떻게 변하는지 보자. 먼저 확인할 수 있는 것은 위치가 변하지 않은 수들간(검정색 수들)의 역접 여부는 변하지 않는다는 사실이다. 위치가 변하는 값(빨간색 수)과 변하지 않는 값들 사이의 역접 여부와, 위치가 변하는 두 값 사이에 역접 여부는 변할 수 있으므로 역접의 수에 영향을 줄 수 있다.
그리고 위치가 변하는 두 값(4와 7) 사이에 위치한 값들간의 관계만이 연산 후 역접의 수에 영향을 준다는 사실도 알 수 있다. (4의 왼쪽 수들을 4가 오른쪽으로 더 이동하더라도 4와의 역접 여부는 변하지 않는다. 마찬가지로 7의 오른쪽 수들은 7이 왼쪽으로 더 이동하더라도 7과의 역접 여부는 변하지 않는다)
위치 \(l\) 과 \(r\) 의 값을 교환했을 때, 그들과 그들 사이에 있는 값들과의 역접 여부가 어떻게 변하는지 따져보면 아래와 같이 세부적으로 정리할 수 있다.
- \((l, \ r)\) 중 \(a[l]\) 보다 큰 값들의 수만큼 역접의 수는 늘어난다.
- \((l, \ r)\) 중 \(a[l]\) 보다 작은 값들의 수만큼 역접의 수는 줄어든다.
- \((l, \ r)\) 중 \(a[r]\) 보다 큰 값들의 수만큼 역접의 수는 줄어든다.
- \((l, \ r)\) 중 \(a[r]\) 보다 큰 값들의 수만큼 역접의 수는 늘어난다.
- \(a[l] < a[r]\) 이면 역접의 수가 1 증가하고, \(a[l] > a[r]\) 이면 역접의 수가 1 감소한다.
위의 내용들에서 서로 상쇄되는 것들을 제거하고, 통합하면 아래와 같이 간결하게 역접의 수 변화를 확인할 수 있다.
- \(a[l] < a[r]\) 이면, \((l<i<r)\) 에 대하여 '(\(a[l]<a[i]<a[r]\) 인 \(i\) 의 개수) \(\times \ 2 + 1\)' 만큼 역접의 수가 증가한다.
- \(a[l] > a[r]\) 이면, \((l<i<r)\) 에 대하여 '(\(a[l]>a[i]>a[r]\) 인 \(i\) 의 개수) \(\times \ 2 + 1\)' 만큼 역접의 수가 감소한다.
위에서 정리한대로라면, 구간 \((l, \ r)\) 에서 두 원소 \(a[l]\) 와 \(a[r]\) 사이에 존재하는 값의 개수를 최대한 빠르게 세는 것이 문제를 해결하는 관건이 된다.
구간 \((l, \ r)\) 에서 두 원소 \(a[l]\) 와 \(a[r]\) 사이에 존재하는 값의 개수를 빠르게 세기 위해서 우리는 평방 분할 기법(square root decomposition)과 펜윅 트리(fenwick tree)를 이용할 수 있다. 순열 \(a[ \ ] = \{1, 2, ..., n\}\) 를 \(\sqrt{n}\) 크기의 블록들로 분할한 후, 각 블록마다 어떤 원소값이 블록에 포함되어 있는지를 펜윅 트리로 표현(있으면 1, 없으면 0)해두면 된다. 그러면 각 블록에서 \(a[l]\) 와 \(a[r]\) 사이에 존재하는 값의 개수를 \(O(log_2n)\) 만에 구할 수 있고, 전체 \(q\) 번의 질문에 \(O(q \times \sqrt{n} \times log_2n)\)의 시간이 소요된다.
'알고리즘 문제 풀이' 카테고리의 다른 글
CF 864E Fire (0) | 2017.10.19 |
---|---|
평방 분할 기법 (Square Root Decomposion Technique) (0) | 2017.03.27 |
777E Hanoi Factory (0) | 2017.03.02 |
777D Cloud of Hashtags (0) | 2017.03.01 |
777C Alyona and Spreadsheet (0) | 2017.03.01 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- sort
- implementation
- parametric search
- pattern matching
- Fenwick Tree
- BFS
- Strings
- branch and bound
- sliding window
- Dynamic Programming
- divide and conquer
- greedy
- Data structure
- kmp search
- math
- Graph
- suffix array
- karatsuba
- Heap
- tree
- search
- Segment Tree
- Square root decomposition
- constructive algorithms
- Binary search
- Minimum Spanning Tree
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
글 보관함