백준

백준 2042 구간 합 구하기 (파이썬) (세그먼트)

MC류짱 2022. 12. 5. 21:26

풀이

import sys; from math import ceil, log

def main(node, start, end):
    if start == end:
        tree[node] = nums[start]
        return tree[node]
    else:
        tree[node] = main(node*2, start, (start+end)//2) + main(node*2+1, (start+end)//2+1, end)
        return tree[node]

def sub_sum(node, start, end, left, right):
    if start > right or end < left:
        return 0

    if left <= start and right >= end:
        return tree[node]

    return sub_sum(node*2, start, (start+end)//2, left, right) + sub_sum(node*2+1, (start+end)//2+1, end, left, right)


# 요소가 바뀌는 경우의 구간 합 구하기 -> 세그먼트 트리 사용 이유
# 일단 start와 end가 움직이며 값을 바꿀 것,
def update(node, start, end, idx, val):
    # 이 범위에 idx 없으면 return
    if start > idx or idx > end:
        return
    # return 안했으면 일단 값 바꿔주고
    tree[node] += val

    # 리프노드까지 계속 들어가야됨
    if start != end:
        update(node*2, start, (start+end)//2, idx, val)
        update(node*2+1, (start+end)//2+1, end, idx, val)

if __name__ == '__main__':
    N, M, K = map(int, sys.stdin.readline().strip().split())
    nums = []
    for _ in range(N):
        nums.append(int(sys.stdin.readline().strip()))

    tree = [0] * 2**(ceil(log(N, 2)) + 1)
    main(1, 0, N-1)
    for _ in range(M+K):
        a, b, c = map(int, sys.stdin.readline().strip().split())
        if a == 1:
            # 기존 값과의 차이
            diff = c-nums[b-1]
            # 기존에 있는 값을 바꿔주고
            nums[b-1] = c
            # 트리 업데이트
            update(1, 0, N-1, b-1, diff)
        elif a == 2:
            print(sub_sum(1, 0, N-1, b-1, c-1))

 


후기

  • 이번 코드는 저번 구간 합 구하기 4에서 update함수만 추가되어서 이 부분만 설명할게요
  • ↓ 구간 합 구하기 4 (세그먼트 트리의 생성 및 구간 합 구하는 코드)
  • https://ryuwc.tistory.com/193
  • 이번에는 위의 링크에서 이어서 update함수만 만들어주면 된다.
  • update할 때에는 일단 최상단 1번 노드부터 바꾸며 시작 (요소 한개가 바뀌면 일단 전체 합도 바뀜)
  • 그리고 점점 쪼개서 들어가서 idx에서 벗어나면 return 하고 idx가 범위에 포함되면 바꿔
  • 위의 과정을 리프노드까지 진행
  • 그림으로 그리면서 설명하면 편한데, 태블릿이 없어서 설명 못함
  • 직접 그려보며 코드를 짜보시오