A_
1. A. Strange Device
시간
이 두 조건을 하나의 조건으로 합칠 수 있는데,
따라서 구간
2. B. Bridges
2.1. Subtask 1
- 단순히 앞에서부터 쿼리를 처리하면서 간선의 무게 제한을 Update 해준다.
- 2번 쿼리가 들어오면 DFS나 BFS 같은 그래프 탐색 알고리즘을 통해 도착할 수 있는 섬의 수를 구하면 된다.
2.2. Subtask 2
- 그래프가 아닌 직선에서 문제를 해결하는 서브태스크다.
- 각 2번 쿼리에 대해 직선에서 왼쪽, 오른쪽으로 이동하면서 처음으로 만날 수 있는
미만의 무게 제한을 가진 간선을 찾으면 각 2번 쿼리에 답할 수 있다. - Segment Tree를 사용하여 각 구간에 포함된 간선들의 무게 제한 중 최솟값을 저장하고 있으면 Binary Search를 사용하거나 Segment Tree 내부 처리를 통해
미만의 무게 제한을 가진 가장 가까운 간선을 찾을 수 있다.
2.3. Subtask 4
- 서브태스크 4가 서브태스크 3보다 쉽다...
- 간선 무게 제한 Update 연산이 없으므로 Query 연산(2번 쿼리)과 기존에 주어진 간선에서 주어진 무게 내림차순으로 정렬하여 오프라인으로 쿼리를 해결할 수 있다.
- Union & Find를 통해 간선으로 이어진 섬을 하나의 그룹으로 묶어주고, Query 연산이 주어지면
가 포함된 그룹에 속한 섬 개수가 해당 쿼리에 대한 답이 된다.
2.4. Full Solution
Subtask 4의 아이디어에 Sqrt Decomposition의 아이디어를 사용하여 해결할 수 있다.
- 앞에서부터
SZ
개의 쿼리를 묶어서 처리한다고 생각하자. SZ
개의 쿼리에는 1번 쿼리와 2번 쿼리가 섞여 있지만, 1번 쿼리도 최대 SZ개, 2번 쿼리도 최대SZ
개 존재한다는 것을 생각할 수 있다.SZ
개 쿼리에 1번 쿼리에 의해 무게 제한이 바뀌는 에지들과(최대SZ
개) 무게 제한이 바뀌지 않는 에지들(최대M
개)를 구분하여 생각하자.- 무게 제한이 바뀌지 않는 간선
(최대M
개) - 오프라인 쿼리를 처리하듯이 2번 쿼리의 무게 제한
와 의 무게 제한 을 기준으로 무게 내림차순 정렬하여 처리한다. 간선들을 처리할 때 간선이 잇는 두 섬을 Union & Find 알고리즘을 사용하여 한 그룹으로 묶어준다.- 이렇게 처리하면 2번 쿼리
를 처리할 때 무게 제한이 바뀌지 않는 에지들 들 중 무게 제한 이 이상인 에지들을 통해 연결되어 있는 섬들을 Union & Find로 합쳐져 있는 상태를 유지할 수 있다. - 무게 제한이 바뀌는 간선
(최대SZ
개) - 2번 쿼리
를 처리하기 전에 그 쿼리보다 먼저 주어진 1번 쿼리들을 처리해 줘야 한다. - 각 2번 쿼리
를 처리할 때 무게 제한이 바뀌는 간선 에 대해 다음 두 조건을 모두 검사한다. (최대SZ
개이기 때문에 모두 처리가 가능하다) 보다 먼저 주어진 쿼리- 다리 무게 제한
가 보다 크다
- 위 두가지 조건을 모두 만족하는 경우 Union & Find로
가 잇는 두 섬을 한 그룹으로 묶어준다. - 이때 사용하는 Union & Find는 되돌릴 수 있는 연산이여야 하기 때문에 Path Compression이 아닌 Rank/Size Compression을 사용하여야 함을 알 수 있다.
- 무게 제한이 바뀌지 않는 간선
- 각 2번 쿼리에 대해 위와 같이 간선들을 따로 처리하면 Union & Find를 통해 같은 그룹으로 섬들을 묶고
와 같은 그룹의 섬 개수를 구해주면 문제를 해결할 수 있다. - 이때
SZ
의 값은 Sqrt Decomposition에서 그룹 개수를 루트로 설정하는 것과 같이 시간복잡도를 최소화할 수 있는 값으로SZ
를 설정하면 된다.
3. C. Street Lamps
3.1. Subtask 1
- 각 쿼리
(a, b)
에 대해 그 전까지의 가로등 반전(최대N
개)을 해보면서 매 시간(a, b)
가 연결되어 있는지 확인한다. (a, b)
사이 인 가 없으면(a, b)
가 연결되어 있다는 것을 알 수 있는데 이것은 구간 내 0의 개수를 저장한 Segment Tree를 쓰면 쉽게 처리할 수 있고, Set으로 구간을 관리하면서도 처리할 수 있다.
3.2. Subtask 2
- 각 가로등이 켜져 있던 시간을 저장하고 있으면 매번 쿼리에 바로 답할 수 잇다.
번째 가로등이 켜져 있던 시간을 라 하면,- 시간
에 번째 가로등이 켜지면 - 시간
에 번째 가로등이 꺼지면
- 시간
- 시간
에 가로등 에 대한 쿼리가 들어오면- 가로등
가 켜져 있으면 답은 - 가로등
가 꺼져 있으면 답은
- 가로등
3.3. Subtask 3
- 모든 가로등이 꺼지지 않고 켜지기만 한다.
- 정류장
a
와 정류장b
사이가 연결되기 시작한 시간은 정류장a
와 정류장b
사이 존재하는 가로등 중 가장 늦게 켜진 가로등이 켜진 시간일 것이다. - 따라서 연결되지 않은 가로등의 시간을
로 초기화 하고 번째 가로등이 켜진 시간을 Segment Tree에 Update하고, 쿼리를 Segment Tree의 Max 연산으로 처리하면 된다.
3.4. Full Solution
- 이어져 있는 가로등의 구간을 Pair를 관리하는 Set으로 저장하여 관리한다.
- Subtask 2와 같이 가로등이 켜져 있던 시간을 저장하면서 쿼리를 처리한다.
- 가로등 구간을 Set으로 관리하면 구간이 생기거나 없어지는 것을 관리할 수 있다.
- Subtask 2와 다른 점은 구간
(a, b)
가 시간i
에 생기거나 없어지면 인 모든 구간(x, y)
에 대해 에 특정 값을 더하거나 빼줘야 한다. - 따라서 이를 2D Dynamic Segment Tree를 사용하여 처리하면 전체 문제를 Subtask 2와 같은 방식으로 해결할 수 있다.