====== 디지털 비디오 디스크(DVDs) ====== ===== 풀이 ===== * n개의 서로 다른 수가 있을 때, 이 수들이 x, x+1, ..., x+n-1 인지를 확인하는 방법은 일일히 정렬해서 비교해볼 필요 없이, 그냥 최댓값이 x+n-1이고 최솟값이 x인지만 확인해보면 된다. * 이 아이디어를 이 문제에 그대로 적용하면, 구간에 있는 DVD번호가 A, A+1, ..., B인지를 확인하려면, 구간의 최댓값과 최솟값만을 계산할 수 있으면 된다. 그것은 세그먼트 트리로 O(logn)에 가능하다. * 위치를 바꾸는 것은 두번의 포인트 업데이트 쿼리. 카운터에 가져온 DVD를 확인하는 것은 구간 최솟값과 구간 최댓값 쿼리가 필요하다. 모두 O(logn)에 가능하므로, 쿼리를 처리하는 데에는 총 O(qlogn)의 시간 복잡도. 그리고 처음에 세그먼트 트리를 구축하는데에도 O(n)이 걸리므로 모두 합치면 O(n+qlogn)이다 * 원래 (최솟값,최댓값)의 튜플을 저장하는 세그먼트 트리로 구현했었는데 시간이 빡빡했다. Python으로는 시간 초과, PyPy를 써서 겨우 1800ms 정도에 통과.. 코드가 덜 깔끔하긴 하지만 튜플을 쓰지 않고, 최솟값을 저장하는 세그트리와 최댓값을 저장하는 세그트리로 나눠서 구현했더니 시간이 200~300ms 정도로 단축되었다. * 여기서 더 나아가서, 최댓값과 최솟값 대신에, 최솟값과 합을 이용해서 체크하는 것으로 로직을 바꿨다. 이렇게 해도 n개의 수가 조건을 만족하는지 체크는 가능하고, 합은 펜윅트리를 쓸수 있으니까 조금 더 빨라진다. 최솟값 세그트리와 합 펜윅트리를 이용해서 구현한 결과 아슬아슬하게 7452ms로 통과시키는 데에 설공. * 새롭게 만든 [[:ps:teflib:segmenttree#MinSegmentTree|teflib.segmenttree.MinSegmentTree]]를 사용해보았다. (RMQ에 최적화된 세그트리 구현..). 이렇게 하자, 굳이 펜윅트리와 세그트리 두개를 같이 쓰지 않더라도, 최댓값 세그트리와 최솟값 세그트리를 사용해서 통과되었다. ===== 코드 ===== ==== 코드 1 - 최솟값 세그트리 + 구간합 펜윅트리 ==== """Solution code for "BOJ 9345. 디지털 비디오 디스크(DVDs)". - Problem link: https://www.acmicpc.net/problem/9345 - Solution link: http://www.teferi.net/ps/problems/boj/9345 """ import sys from teflib import fenwicktree from teflib import segmenttree def main(): T = int(sys.stdin.readline()) for _ in range(T): N, K = [int(x) for x in sys.stdin.readline().split()] min_segtree = segmenttree.SegmentTree(range(N), merge=min) fenwick_tree = fenwicktree.FenwickTree(range(N)) dvd_by_pos = list(range(N)) for _ in range(K): Q, A, B = [int(x) for x in sys.stdin.readline().split()] if Q == 0: dvd_at_a, dvd_at_b = dvd_by_pos[A], dvd_by_pos[B] min_segtree.set(A, dvd_at_b) min_segtree.set(B, dvd_at_a) fenwick_tree.set(A, dvd_at_b) fenwick_tree.set(B, dvd_at_a) dvd_by_pos[A], dvd_by_pos[B] = dvd_at_b, dvd_at_a else: s = (A + B) * (B - A + 1) // 2 if (fenwick_tree.query(A, B + 1) == s and min_segtree.query(A, B + 1) == A): print('YES') else: print('NO') if __name__ == '__main__': main() * Dependency: [[:ps:teflib:fenwicktree#FenwickTree|teflib.fenwicktree.FenwickTree]], [[:ps:teflib:segmenttree#SegmentTree|teflib.segmenttree.SegmentTree]] ==== 코드 1 - 최솟값 세그트리 + 최댓값 세그트리 ==== """Solution code for "BOJ 9345. 디지털 비디오 디스크(DVDs)". - Problem link: https://www.acmicpc.net/problem/9345 - Solution link: http://www.teferi.net/ps/problems/boj/9345 """ import sys from teflib import segmenttree def main(): T = int(sys.stdin.readline()) for _ in range(T): N, K = [int(x) for x in sys.stdin.readline().split()] min_segtree = segmenttree.MinSegmentTree(range(N)) max_segtree = segmenttree.MinSegmentTree(range(0, -N, -1)) dvd_by_pos = list(range(N)) for _ in range(K): Q, A, B = [int(x) for x in sys.stdin.readline().split()] if Q == 0: dvd_at_a, dvd_at_b = dvd_by_pos[A], dvd_by_pos[B] min_segtree.set(A, dvd_at_b) min_segtree.set(B, dvd_at_a) max_segtree.set(A, -dvd_at_b) max_segtree.set(B, -dvd_at_a) dvd_by_pos[A], dvd_by_pos[B] = dvd_at_b, dvd_at_a else: if (-max_segtree.query(A, B + 1) == B and min_segtree.query(A, B + 1) == A): print('YES') else: print('NO') if __name__ == '__main__': main() * Dependency: [[:ps:teflib:segmenttree#MinSegmentTree|teflib.segmenttree.MinSegmentTree]] {{tag>BOJ ps:problems:boj:플래티넘_3}}