2020년 5월 14일 논산훈련소에 입대한 태상이는 첫 총기 훈련에서 가스 조절기를 잃어버리는 중대한 실수를 범했다. 그로 인해, 태상이는 조교들에게 눈총을 받게 되었다. 조교들은 태상이에게 연병장(운동장)의 흙을 옮기는 일을 주고 제대로 수행하지 못하면 징계를 내리려고 한다.
연병장은 일렬로 이어진 N개의 칸으로 이루어져 있으며 각 칸마다 높이를 가지고 있고, 첫 번째 칸부터 순서대로 1번, 2번, 3번, ..., N번 칸으로 명칭이 붙어있다. 조교들은 총 M명이 있으며, 각 조교들은 태상이에게 a번 칸부터 b번 칸까지 높이 k만큼 흙을 덮거나 파내라고 지시한다. 흙은 주변 산에서 얼마든지 구할 수 있으므로 절대로 부족하지 않다.
태상이는 각 조교의 지시를 각각 수행하면, 다른 조교의 지시로 흙을 덮어둔 칸을 다시 파내기도 하는 비효율적인 일이 발생하는 것을 깨달았다. 그래서 태상이는 각 조교의 지시를 모아 연병장 각 칸의 최종 높이를 미리 구해 한 번에 일을 수행하려고 한다.
k ≥ 0인 경우 a번 칸부터 b번 칸까지 높이가 각각 |k| 만큼 늘어나도록 흙을 덮어야 한다. k < 0인 경우 a번 칸부터 b번 칸까지 높이가 각각 |k| 만큼 줄어들도록 흙을 파내야 한다.
출력
모든 지시를 수행한 뒤 연병장 각 칸의 높이를 공백을 사이에 두고 출력한다.
입력 예시
10 3
1 2 3 4 5 -1 -2 -3 -4 -5
1 5 -3
6 10 5
2 7 2
출력 예시
-2 1 2 3 4 6 5 2 1 0
풀이
누적 합으로 풀이를 시도해보자.
구간 업데이트 쿼리가 반복해서 들어올 때
그리고 그 구간 자체의 크기와, 쿼리 자체의 크기가 충분히 클 때
누적합으로 효율적으로 해결할 여지가 있다.
흙을 파내거나, 혹은 쌓는 구간이 랜덤하게 들어오고 그 구간의 최대 크기는 10^6, 그리고 그 쿼리 역시 10^6에 달한다. 따라서 시작구간과 종료구간 a, b+1에 대해 증감량을 업데이트. 그리고 누적합으로 총 증감량을 갱신. 마지막으로 원래 흙의 높이와 증감량을 토대로 최종값을 출력하면 된다. 총 시간복잡도는 O(M+N)이 된다.
풀이 코드(Python)
import sys
input = sys.stdin.readline
N, M = 0, 0
lands = []
changes = []
def init() :
global lands, changes, N, M
N, M = map(int, input().split())
lands = list(map(int, input().split()))
changes = [0]*(N+1)
def query() :
for _ in range(M) :
a, b, k = map(int, input().split())
changes[a-1] += k
changes[b] -= k
for i in range(N) :
changes[i+1] += changes[i]
lands[i] += changes[i]
print(*lands)
if __name__ == "__main__" :
init()
query()
풀이 코드(Go)
package main
import (
"bufio"
"fmt"
"os"
)
var (
reader *bufio.Reader = bufio.NewReader(os.Stdin)
writer *bufio.Writer = bufio.NewWriter(os.Stdout)
lands []int
changes []int
n, m int
)
func initalize() {
var land int
fmt.Fscanln(reader, &n, &m)
lands = make([]int, n)
changes = make([]int, n+1)
for i := 0; i < n; i++ {
fmt.Fscan(reader, &land)
lands[i] = land
}
fmt.Fscanln(reader)
}
func query() {
var a, b, k int
for i := 0; i < m; i++ {
fmt.Fscanln(reader, &a, &b, &k)
changes[a-1] += k
changes[b] -= k
}
for i := 0; i < n; i++ {
changes[i+1] += changes[i]
fmt.Fprintf(writer, "%d ", lands[i] + changes[i])
}
}
func main() {
defer writer.Flush()
initalize()
query()
}