3. POSTECH Computer Algorithm Team
- Input이 1개 들어올 때 Output을 출력하는게 기존 문제
- Input이 여러 개 들어올 때 적절한 Output을 출력하는게 쿼리 문제
- 기존 문제를 쿼리 문제로 나눌 수 있고, 반대로 쿼리 문제를 기존의 문제로 바꿀 수 있다.
- 그러므로, 사실 크게 의미 없는 분류다(…)
쿼리 문제
Query Problem
4. POSTECH Computer Algorithm Team
Query Problem
적절한 문제공간
Array,
Graph,
Tree,
….
쿼리 1
쿼리 2
쿼리 3
쿼리 4
쿼리 5
쿼리 6
출력 1
출력 2
출력 3
출력 4
출력 5
출력 6
5. POSTECH Computer Algorithm Team
Query Problem
다음 문제를 풀어보자.
Q) A[1, 2, … , n]이 주어지며, 2종류의 쿼리가 주어진다.
- 쿼리 1 : (u, v)가 주어지면, A[u, u+1, … , v]를 출력한다.
- 쿼리 2 : (u, k)가 주어지면, A[u]에 k를 더한다.
- 여러 개의 쿼리들이 주어질 때, 어떻게 풀까?
6. POSTECH Computer Algorithm Team
Query Problem
A1)
- 무작정 다 더한다!
- 쿼리 1 (u, v)가 주어지면, for문으로 u부터 v까지 더하여 출력한다.
- 쿼리 2 (u, k)가 주어지면, 그냥 A[u]에 k를 더한다.
- 쿼리 1 수행하는데 걸리는 시간 : O(n)
- 쿼리 2 수행하는데 걸리는 시간 : O(1)
- 정말 간단한 풀이지만, 당연하게도(?) 시간이 터진다.
7. POSTECH Computer Algorithm Team
Query Problem
A2)
- 크기가 n인 array S를 정의하자.
- 처음에는 S[i] = A[1] + … + A[i]로 초기화한다.
- 쿼리 1 (u, v)가 주어지면 S[v] – S[u-1]을 출력한다.
- 쿼리 2 (u, k)가 주어지면, S[u, …, n]에 k를 더한다.
- 쿼리 1 수행하는데 걸리는 시간 : O(1)
- 쿼리 2 수행하는데 걸리는 시간 : O(n)
- 안타깝게도, 또 터진다(…)
8. POSTECH Computer Algorithm Team
Query Problem
- 쿼리 문제는 쿼리를 실행하기 전 준비를 하는 전처리 시간,
쿼리를 수행하는데 걸리는 시간인 후처리 시간이 존재한다.
- 대부분 전처리 시간과 후처리 시간은 반비례한다.
- 쿼리 1 수행 시간과 쿼리 2 수행 시간도 대부분 반비례한다.
- 그러므로 전처리 시간, 후처리 시간을 “적절히” 조정해야 원하는 시간 안에 수행이 가능하다.
9. POSTECH Computer Algorithm Team
Query Problem
A1, A2의 문제점
- A1 : 너무 잘게 잘라서 연산한다!
- 첫번째 쿼리를 수행할 때 값을 한 개씩 더해주므로 시간이 오래 걸린다…
- A2 : 너무 안 잘라서 연산한다!
- 첫번째 쿼리를 수행할 때 값 2개만 더하므로 두번째 쿼리를 실행할 때 수행이 너무 오래 걸린다.
그러므로, 첫번째 쿼리와 두번째 쿼리 모두 적당히 걸리는 풀이가 제일 좋은 풀이일 것이다.
이를 해결하기 위해 ‘Interval’을 사용한다.
10. POSTECH Computer Algorithm Team
Query Problem
- 적당한 Interval이 존재한다고 하자.
- 모든 Interval은 기존에 있는 적당한 Interval들을 더해서 만들 수 있다고 하자.
- 그렇다면, 고려해야 하는 경우의 수가 매우 줄어든다!!
- 이유 : 모든 Interval은 n^2개 정도 있는데, 적당한 Interval들의 수는 n^2개보다 훨씬 적기 때문.
- 어떻게 적당한 Interval을 만들까?
- 균등 Interval : Bucket
- 비균등 Interval : Segment Tree, Penwick Tree
11. POSTECH Computer Algorithm Team
Query Problem
A1의 적당한 Interval은 다음과 같다.
- [1], [2], [3], … , [n]
A2의 적당한 Interval은 다음과 같다.
- [1], [1,2], [1,2,3], … , [1,2,…,n]
Penwick Tree, Segment Tree의 Interval은 다음과 같다.
- [1], [2], … , [n], [1,2], [3,4], … , [1,2,3,4], [5,6,7,8], … , [1,2,…,2^k]
12. POSTECH Computer Algorithm Team
- Segment Tree는 다음과 같이 생겼습니다.(N=8인 경우로 가정합시다)
- Leaf node에는 실제 값이 저장되어 있습니다.
Segment Tree
Segment Tree
[1] [2] [3] [4] [5] [6] [7] [8]
[1,2] [3,4] [5,6] [7,8]
[1,2,3,4] [5,6,7,8]
[1,2,3,4,5,6,7,8]
13. POSTECH Computer Algorithm Team
Penwick Tree
- 일반적으로 모든 Interval은 Segment Tree의 Interval O(logN)개 정도의 합으로 표현할 수 있다.
- 그리고 어떠한 원소의 값을 참조할 때 Segment Tree의 Interval logN개만 참조하면 원래 값도 알 수 있다.
- 그러므로, 쿼리 1과 쿼리 2의 수행시간은 O(logN)
- 쿼리 1과 2의 수행시간이 적당히 Balance를 이룬다!
Q) 어떻게 임의의 Interval을 O(logN)개의 Interval만으로 표현할 수 있을까?
14. POSTECH Computer Algorithm Team
- Segment Tree는 bottom up, top down 두 가지 방식으로 구현할 수 있다.
- DP와 비슷하게, top down은 재귀함수로, bottom up은 반복문으로 구현할 수 있다.
- Bottom up의 경우, size를 2^k + n으로 맞춰야 한다.
구현
Segment Tree
15. POSTECH Computer Algorithm Team
쿼리 1 처리 방법
- Penwick Tree의 제일 아래부터, 처리하고 싶은 Interval의 끝부분들이 어디에 있는지 확인한다.
- 왼쪽 끝 : 자신의 부모의 right자식이면, 처리하고 오른쪽으로 shift
- 오른쪽 끝 : 자신의 부모의 left자식이면, 처리하고 왼쪽으로 shift
- 이 이외의 경우는, 그냥 부모로 올라간다.
상향식
Segment Tree
16. POSTECH Computer Algorithm Team
Segment Tree
- [2,8]을 처리한다고 하자.
- 2는 [1,2]의 오른쪽 자식이므로, [2,8] = [2] + [3,8]로 분해
[1] [2] [3] [4] [5] [6] [7] [8]
[1,2] [3,4] [5,6] [7,8]
[1,2,3,4] [5,6,7,8]
[1,2,3,4,5,6,7,8]
17. POSTECH Computer Algorithm Team
Segment Tree
- 3과 8은 문제 없으므로, 부모로 올라간다.
- [2]는 그냥 [2]
[1] [2] [3] [4] [5] [6] [7] [8]
[1,2] [3,4] [5,6] [7,8]
[1,2,3,4] [5,6,7,8]
[1,2,3,4,5,6,7,8]
18. POSTECH Computer Algorithm Team
Segment Tree
- [3,4]는 [1,2,3,4]의 오른쪽 자식이므로, [3,8] = [3,4] + [5,8] 분해
- [5,8]은 문제가 없으니 부모로 올라간다.
[1] [2] [3] [4] [5] [6] [7] [8]
[1,2] [3,4] [5,6] [7,8]
[1,2,3,4] [5,6,7,8]
[1,2,3,4,5,6,7,8]
19. POSTECH Computer Algorithm Team
Segment Tree
- [5,8]은 부모에서 전부 처리 가능.
- 즉, [2,8] = [2] + [3,4] + [5,6,7,8]
[1] [2] [3] [4] [5] [6] [7] [8]
[1,2] [3,4] [5,6] [7,8]
[1,2,3,4] [5,6,7,8]
[1,2,3,4,5,6,7,8]
20. POSTECH Computer Algorithm Team
Segment Tree
쿼리 2 처리 방법
- 찾고 싶은 값들의 부모 interval들만 참조하면 됩니다.
[1] [2] [3] [4] [5] [6] [7] [8]
[1,2] [3,4] [5,6] [7,8]
[1,2,3,4] [5,6,7,8]
[1,2,3,4,5,6,7,8]
22. POSTECH Computer Algorithm Team
- 하향식은 상향식과 달리, size를 맞춰줄 필요가 없다.
- 쿼리 1, 2에 대한 처리는 상향식과 완전히 반대로 생각하면 된다.
하향식
Segment Tree
23. POSTECH Computer Algorithm Team
Segment Tree
- [2,8]을 계산한다고 하자.
- 먼저, root부터 탐색을 시작한다.
[1] [2] [3] [4] [5] [6] [7] [8]
[1,2] [3,4] [5,6] [7,8]
[1,2,3,4] [5,6,7,8]
[1,2,3,4,5,6,7,8]
24. POSTECH Computer Algorithm Team
Segment Tree
- [1,2,3,4]와 [5,6,7,8]은 [2,8]과 겹치는 부분이 있다.
- 고로, 두 쪽 다 탐색한다.
[1] [2] [3] [4] [5] [6] [7] [8]
[1,2] [3,4] [5,6] [7,8]
[1,2,3,4] [5,6,7,8]
[1,2,3,4,5,6,7,8]
25. POSTECH Computer Algorithm Team
Segment Tree
- [5,6,7,8]은 [2,8]안에 완전히 속하므로 정지
- [1,2,3,4]는 [2,8]과 부분만 겹치므로 또 나눈다.
[1] [2] [3] [4] [5] [6] [7] [8]
[1,2] [3,4] [5,6] [7,8]
[1,2,3,4] [5,6,7,8]
[1,2,3,4,5,6,7,8]
26. POSTECH Computer Algorithm Team
Segment Tree
- [1]은 [2,8]과 겹치는 부분이 하나도 존재하지 않는다.
- 그러므로 [1]은 삭제, 그러면 [2,8] = [2] + [3,4] + [5,6,7,8]
[1] [2] [3] [4] [5] [6] [7] [8]
[1,2] [3,4] [5,6] [7,8]
[1,2,3,4] [5,6,7,8]
[1,2,3,4,5,6,7,8]
27. POSTECH Computer Algorithm Team
Segment Tree
쿼리 2 처리 방법
- 찾고 싶은 index가 속해있는 자손 노드를 따라, leaf node까지 가면 됩니다.
[1] [2] [3] [4] [5] [6] [7] [8]
[1,2] [3,4] [5,6] [7,8]
[1,2,3,4] [5,6,7,8]
[1,2,3,4,5,6,7,8]
30. POSTECH Computer Algorithm Team
Lazy Propagation
Segment Tree를 사용하여 이 문제를 풀어보도록 하자.
- Segment Tree를 이용하면 A[u]에 k를 O(logn)만에 update할 수 있다.
- 이를 이용해 값들 각각 update하면 쿼리 3을 해결해 줄 수 있다.
- 그 경우, 쿼리 3의 수행시간 : O(nlogn)!!!!
Q) 왜 이렇게 수행시간이 많이 걸리게 된 것일까?
31. POSTECH Computer Algorithm Team
Lazy Propagation
- 문제는 이전에 말했던 것과 같다. 너무 잘게 잘라서 연산한다!
- 쿼리 1에 대해서는 적당히 잘라서 연산을 해주는데,
정작 값을 구할 때는 잘게 잘라서 연산하기 때문에 시간이 오래 걸린다.
- 즉, 쿼리 3을 계산할 때도 적당히 잘라 연산하는게 필요하다.
32. POSTECH Computer Algorithm Team
Lazy Propagation
- 1을 100번 더하던 100을 1번 더하던 값은 같다.
- 그렇다면, 1을 100번 더하는 “부지런한 연산” 보다는 100을 1번 더하는 “게으른 연산”이 훨씬 효율적이다.
- 그러므로, 어떤 Interval에 대해 쿼리 연산을 할 때 비슷한 연산이 들어오면,
연산들을 묶어서 한번만 연산하도록 바꾸면 게으른 연산이 가능하다.
Q) 언제 연산하도록 해야 할까?
33. POSTECH Computer Algorithm Team
Lazy Propagation
A) 해당하는 Interval의 값을 요구하는 query가 날라오면, 그 때 연산을 수행하면 된다.
- 이것이 바로 Lazy Propagation의 원리
- Lazy Propagation을 할 수 있는 기본 조건 : 각 쿼리 연산들은 “merge”가 가능해야 한다.
- 다른 말로, 누적해서 나중에 연산이 가능해야한다.
34. POSTECH Computer Algorithm Team
Lazy Propagation
- Lazy Propagation은 top-down 방식의 탐색을 요구한다.
- 그러므로, 상향식 구현은 Lazy Propagation을 사용하지 못한다.
- Segment Tree는 Lazy Propagation이 가능하고, 이 경우에 사용하는 알고리즘을
Segment Tree with Lazy Propagation이라 한다.