https://www.acmicpc.net/problem/15957


1. 트리


트리의 루트에 쿼리가 가해지면 자식들의 점수가 모두 더해진다.


-> 트리를 dfs 돌면서 번호를 매기면, 루트 노드 부터 자식들이 연속해서 들어있는 배열을 만들 수 있다. = 트리 순회 배열이라고 한단다.



2. 쿼리


트리 순회 배열에 쿼리가 가해진다.


이제 쿼리는 배열의 일부 구간을 증가시키는 쿼리가 된다.


-> 일부 구간을 빠르게 증가시키는 방법이 필요하다.


-> 증가시켰으면 값이 얼마인지도 빠르게 알아낼 방법이 필요하다. = 펜윅트리의 ( range update & point query ) 모드를 사용하자.



3. 펜윅 트리


이 자료구조는 다음 두 기능을 로그시간에 제공하는 자료구조다.


1) update(p, v) : p번째 원소를 v만큼 증가시킨다.


2) query(p) : 첫번째 원소부터 p번째 원소까지의 합을 알려준다.


즉 point update & range query를 로그시간에 수행한다.


이를 조금만 응용하면 range update & point query 모드로 바꿀 수 있다.



원래 배열을 a라고 하고, 배열 b[x] = a[x] - a[x - 1] 이라고 정의해보자.


그러면 이제 a의 입장에서, a[x]는 b[x] + b[x - 1] + ... 즉 누적합이 된다.


이제 두 기능을 b에 대고 수행한다고 생각해보자.


1) update(p, v)


-> 예를 들어 update(3, v)라면, a[1]과 a[2]는 가만히 있고, a[3]부터 v씩 늘어난 것이다. 왜냐하면 b의 정의 때문에.


따라서 [from, to] 구간을 v만큼 증가시키고 싶다면, update(from, v) 와 update(to + 1, v) 두 번으로 배열 a를 다 조질수 있다.


2) query(p)


-> b[1] + b[2] + ... + b[p] = a[p] 이니까, a의 p번째 원소 값을 구하는 쿼리로 변경되었다.



이처럼 펜윅트리는


1) point update & range query


2) range update & point query


3) range update & range query


총 3가지 모드를 제공한다. 3번째 모드는 차후에 설명하는 것으로.. ㅎㅎ




이제 트리에 가해지는 쿼리를, 펜윅트리에서 로그시간에 수행할 수 있게 되었다.


하지만


1) 모든 쿼리를 수행해보면서 매번 모든 가수가 평균 점수를 넘는지 확인


2) 모든 가수마다 쿼릐를 수행해보면서 언제 평균 점수를 넘는지 확인


어떤 방법으로도 N * K * log(N)으로 시간이 오바된다.



4. 시간 줄이기


포인트는 가수들의 평균점수는 쿼리들이 수행되는 동안 절대 내려가지 않는다는 점이다.


따라서 단조증가하고, 이는 이분 탐색을 떠올리게 해준다.


하지만 가수마다 이분 탐색으로 조지는 것 보다, 모든 가수들의 구간을 줄여나가는 방법이 있단다. -> 병렬 이분 탐색



이 알고리즘의 구조를 보면, 가수마다 구간이 있고 구간의 중앙값은 타겟이 된다.


이제 쿼리를 순차적으로 수행할 텐데, 현재 수행하는 쿼리가 타겟과 같다면 그 가수는 구간을 반으로 줄일 수 있다.


쿼리를 전부 수행하고 나서, 구간이 변화한 가수가 있다면, 다시 처음부터 쿼리를 수행하는 짓을 반복한다.


말로는 머가 개선된건지 모르겠지만, 나중에 코드로 보면 더 빠르겠구나 할 꺼다.




'알고리즘 > 미분류' 카테고리의 다른 글

백준) 15668 방 번호  (0) 2018.10.02
백준) 16116 작은 큐브러버  (0) 2018.10.01
codeforces educational 50 round div2 참여기록  (0) 2018.09.09
SCC 문제들! 백준) 2150, 4013, 4196  (0) 2018.07.22
백준) 2512 예산  (0) 2018.07.19

+ Recent posts