본문 바로가기

알고리즘/백준

[백준] 10999번 : 구간 합 구하기2

728x90

10999번: 구간 합 구하기 2

 

10999번: 구간 합 구하기 2

첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)과 M(1 ≤ M ≤ 10,000), K(1 ≤ K ≤ 10,000) 가 주어진다. M은 수의 변경이 일어나는 횟수이고, K는 구간의 합을 구하는 횟수이다. 그리고 둘째 줄부터 N+1번째 줄

www.acmicpc.net

📄 문제개요

구간합을 구하는 문제로, 쿼리와 업데이트가 주어졌을때, 턴마다 결과를 출력하는 문제이다.

🤔 문제분석

구간 업데이트

기존의 구간합 로직으로 구현한다면 시간복잡도는 KlogN이 될것이다. 만약 구간이 엄청 크다면 원하는 시간복잡도안에 문제를 해결 할 수 없습니다.

느리게 갱신되는 세그먼트 트리 (Segment Tree Lazy Propagation)

📝 의사코드

  1. 세그먼트 트리를 초기화 한다.
  2. 쿼리와 업데이트를 분기한다.

💻 코드

import sys
input = sys.stdin.readline

N, M, K = map(int, input().split())

tree_size = 4 * N

arr = [int(input()) for _ in range(N)]

tree = [0 for _ in range(tree_size)]
lazy = [0 for _ in range(tree_size)]

def init(start, end, node):
    if start == end:
        tree[node] += arr[start]
    else:
        mid = (start + end) // 2
        init(start, mid, node * 2)
        init(mid+1, end, node * 2 + 1)
        tree[node] = tree[node * 2] + tree[node * 2 + 1]

def update_lazy(start, end, node):
    if lazy[node] != 0:
        tree[node] += lazy[node] * (end - start + 1)
        if start != end:
            lazy[node * 2] += lazy[node]
            lazy[node * 2 + 1] += lazy[node]
        lazy[node] = 0
    
def update(start, end, left, right, node, diff):
    update_lazy(start, end, node)
    if left > end or right < start:
        return
    
    if start >= left and end <= right:
        tree[node] += (end - start + 1) * diff
        if start != end:
            lazy[node * 2] += diff
            lazy[node * 2 + 1] += diff
        return
    mid = ( start + end ) // 2
    update(start, mid, left, right, node * 2, diff)
    update(mid + 1, end, left, right, node * 2 + 1, diff)
    tree[node] = tree[node * 2] + tree[node * 2 + 1]
    
def query(start, end, left, right, node):
    update_lazy(start, end, node)
    if left > end or right < start:
        return 0
    if start >= left and end <= right:
        return tree[node]
    mid = ( start + end ) // 2
    lquery = query(start, mid, left, right, node * 2)
    rquery = query(mid + 1, end, left, right, node * 2 + 1)
    return lquery + rquery
    

init(0, N-1, 1)

for _ in range(M+K):
    temp = list(map(int, input().split()))
    if temp[0] == 1:
        b, c, d = temp[1:]
        update(0, N-1, b-1, c-1, 1, d)
    else:
        b, c = temp[1:]
        print(query(0, N-1, b-1, c-1, 1))

🎯 피드백 및 개선사항

처음문제를 접할때, 어떤식으로 최적화 해야할까 고민중, 생각이 잘 떠올리지 않아 인터넷에 찾아보았습니다.

느리게 갱신되는 세그먼트트리 가있었고 해당부분을 참고하여 새로운 알고리즘을 학습하였습니다.

❓다른사람은 어떻게 풀었을까?

해결해야하는 방법이 정형화 되어있습니다.

728x90

'알고리즘 > 백준' 카테고리의 다른 글

[백준] 7578번 : 공장  (1) 2024.01.06
[백준] 11505번 : 구간 곱 구하기  (1) 2024.01.04
[백준] 5676번 : 음주코딩  (1) 2024.01.01
[백준] 18500번 : 미네랄 2  (1) 2023.12.30
[백준] 2637번 : 장난감조립  (0) 2023.12.29