ํ’€์Šคํƒ ์›น๐ŸŒ ๊ฐœ๋ฐœ์ž ์ง€๋ง์ƒ ๐Ÿง‘๐Ÿฝโ€๐Ÿ’ป
โž• ์ธ๊ณต์ง€๋Šฅ ๊ด€์‹ฌ ๐Ÿค–


Categories


Recent views

  • 1
  • 2
  • 3
  • 4
  • 5

Python for Algorithms-Tree

Python for Algorithms-Tree

๋น„์„ ํ˜• ๊ตฌ์กฐ, ์›์†Œ๋“ค ๊ฐ„์— 1:n, ๊ณ„์ธตํ˜• ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง„๋‹ค.

์ƒํ˜ธ ๋ฐฐํƒ€ ์ง‘ํ•ฉ

์„œ๋กœ์†Œ ์ง‘ํ•ฉ(disjoint set) ํ˜น์€ ์ƒํ˜ธ ๋ฐฐํƒ€ ์ง‘ํ•ฉ์€ ์ง‘ํ•ฉ ๊ฐ„์— ์ค‘๋ณต๋˜๋Š”(๊ต์ง‘ํ•ฉ) ์›์†Œ๊ฐ€ ์—†๋Š” ์ง‘ํ•ฉ๋“ค์ด๋‹ค.

๋ฌธ์ œ๋ฅผ ํ’€ ๋•Œ ์„œ๋กœ ๊ต์ง‘ํ•ฉ์ด ์—†๋Š” ์ง‘ํ•ฉ๋“ค์˜ ์ˆ˜ ๋“ฑ์ด ์ฃผ์ œ๋ผ๋ฉด ์ƒ๊ฐํ•ด๋ณผ ๋งŒ ํ•˜๋‹ค.

์ง‘ํ•ฉ์˜ ๋Œ€ํ‘œ์ž(๋ฃจํŠธ)๋กœ ๊ฐ ์ง‘ํ•ฉ์„ ๊ตฌ๋ถ„ํ•œ๋‹ค.

๐Ÿงพ๏ธ ์ƒํ˜ธ ๋ฐฐํƒ€ ์ง‘ํ•ฉ (๋ฐฐ์—ด ๊ตฌํ˜„, $O(N)$) ํ•จ์ˆ˜
p = [i for i in range(node_num)]  # p[x]: ๋…ธ๋“œ x์˜ ๋ถ€๋ชจ ์ €์žฅ
rank = [i for i in range(node_num)]  # rank[x]: ๋ฃจํŠธ ๋…ธ๋“œ๊ฐ€ x์ธ ํŠธ๋ฆฌ์˜ ๋žญํฌ ๊ฐ’ ์ €์žฅ
def make_set(x):
    """์œ ์ผํ•œ ๋ฉค๋ฒ„ X๋ฅผ ํฌํ•จํ•˜๋Š” ์ƒˆ๋กœ์šด ์ง‘ํ•ฉ์„ ์ƒ์„ฑํ•˜๋Š” ์—ฐ์‚ฐ"""
    p[x] = x  # ์ž๊ธฐ์ž์‹ ์ด ๋ฃจํŠธ
    rank[x] = 0  

def find_set(x):
    """ x๋ฅผ ํฌํ•จํ•˜๋Š” ์ง‘ํ•ฉ์„ ์ฐพ๋Š” ์˜คํผ๋ ˆ์ด์…˜ """
    if x != p[x]:    # x๊ฐ€ ๋ฃจํŠธ๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ
    # Path Compression: ํŠน์ • ๋…ธ๋“œ์—์„œ ๋ฃจํŠธ๊นŒ์ง€์˜ ๊ฒฝ๋กœ์— ์กด์žฌํ•˜๋Š” ๋…ธ๋“œ๊ฐ€ ๋ฃจํŠธ๋ฅผ ๋ถ€๋ชจ๋กœ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ๊ฐฑ์‹ , ๋‹จ๋ฐฉํ–ฅ ๊ทธ๋ž˜ํ”„์—์„œ๋งŒ ๊ฐ€๋Šฅํ•จ
        p[x] = find_set(p[x])  # ์–‘๋ฐฉํ–ฅ์ผ ์‹œ ๋‹ค์Œ์œผ๋กœ ๋Œ€์ฒด : return find_set(x)
    return p[x]  

def union(x, y):
    """ x์™€ y๋ฅผ ํฌํ•จํ•˜๋Š” ๋‘ ์ง‘ํ•ฉ์„ ํ†ตํ•ฉํ•˜๋Š” ์˜คํผ๋ ˆ์ด์…˜ """
    link(find_set(x), find_set(y))  

def link(x, y):
    """ ๋‘ ๋ฃจํŠธ๋ฅผ ํ†ตํ•ฉํ•˜๋Š” ์˜คํผ๋ ˆ์ด์…˜ """
    if rank[x] > rank[y]:
        p[y] = x
    else:
        p[x] = y
    if rank[x] == rank[y]:
        rank[y] += 1

์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ

์ด์ง„ ํŠธ๋ฆฌ๋Š” ๋ชจ๋“  ๋…ธ๋“œ๋“ค์ด 2๊ฐœ์˜ ์„œ๋ธŒํŠธ๋ฆฌ๋ฅผ ๊ฐ–๋Š” ํŠน๋ณ„ํ•œ ํ˜•ํƒœ

๋ ˆ๋ฒจ์ด $i$๋ผ๋ฉด ๋…ธ๋“œ์˜ ์ตœ๋Œ€ ๊ฐฏ์ˆ˜๋Š” $2^i$๊ฐœ

์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ๋Š” ํƒ์ƒ‰ ์ž‘์—…์„ ํšจ์œจ์ ์œผ๋กœ ํ•˜๊ธฐ ์œ„ํ•œ ์ž๋ฃŒ ๊ตฌ์กฐ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŠน์„ฑ์„ ๊ฐ€์ง

  • ๊ฐ ๋…ธ๋“œ๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ์œ ์ผํ•œ ํ‚ค(๋ฐ์ดํ„ฐ)๋ฅผ ๊ฐ€์ง„๋‹ค.
  • $์™ผ์ชฝ\ ์ž์‹\ ๊ฐ’ <= ์ž์‹ ์˜\ ๊ฐ’ <= ์˜ค๋ฅธ์ชฝ\ ์ž์‹\ ๊ฐ’$
  • ํŠธ๋ฆฌ๋ฅผ ์ค‘์œ„ ์ˆœํšŒ ์‹œ ์˜ค๋ฆ„์ฐจ ์ˆœ ์ •๋ ฌ์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.
๐Ÿงพ๏ธ ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ ์˜ˆ์‹œ



AVL ํŠธ๋ฆฌ

๐Ÿงพ๏ธ ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ ์˜ˆ์‹œ



์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ (segment tree)

์ˆ˜์—ด์˜ ์ด ํ•ฉ, ์ด ๊ณฑ, ์ตœ๋Œ“๊ฐ’, ์ตœ์†Ÿ๊ฐ’ ๋“ฑ์„ $O(\log N)$์˜ ์‹œ๊ฐ„์— ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ

๐Ÿงพ๏ธ ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ $O(\log n)$ ์˜ˆ์‹œ - ์žฌ๊ท€ ๋ฒ„์ „
import math

def create_seg_tree(num_list):
    tree = [0] * (1 << (math.ceil(math.log2(len(num_list)))+1))
    # ํ•„์š”ํ•œ ๋…ธ๋“œ ์ˆ˜ == ์žŽ์ƒˆ ๋…ธ๋“œ(N) + ๋ถ€๋ชจ ๋…ธ๋“œ(N-1) == 2N - 1
    # ๋”ฐ๋ผ์„œ ๋†’์ด๋ฅผ H๋ผ๊ณ  ๋†“์„ ๋•Œ โˆ‘^{H}_{n=0}2^n >= 2N -1์„ ๋งŒ์กฑํ•ด์•ผ ํ•œ๋‹ค.
    # tree์˜ ํฌ๊ธฐ๋Š” 2์˜ (์˜ˆ์ƒ ํŠธ๋ฆฌ์˜ ๋†’์ด + 1)์Šน์ด๋ฉด ์ ˆ๋Œ€ ๋ถ€์กฑํ•˜์ง€ ์•Š๋‹ค.
    def create_recursive(start, end, index=1):
        '''
        ์žฌ๊ท€๋ฅผ ํ†ตํ•œ ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ์ƒ์„ฑ
        index: ์ฒ˜๋ฆฌ ์ค‘์ธ ๋…ธ๋“œ
        - index *2, index * 2 + 1 : ๋…ธ๋“œ์˜ ์ž์‹ ๋…ธ๋“œ๋“ค
        - ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ์˜ ์ตœ๊ณ  ๋ถ€๋ชจ์ธ 1๋ถ€ํ„ฐ ์‹œ์ž‘, ์ž์‹์„ ๊ฐ€๋ฅดํ‚ค๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ์ง„ํ–‰ํ•จ
        start - mid : ์™ผ์ชฝ ์ž์‹์ด ์ €์žฅํ•˜๋Š” ๊ฐ’
        mid+1 - end : ์˜ค๋ฅธ์ชฝ ์ž์‹์ด ์ €์žฅํ•˜๋Š” ๊ฐ’
        '''
        nonlocal tree
        # tree์˜ leap์— ๋„๋‹ฌํ–ˆ์œผ๋ฉด num_list ๊ฐ’ ๊ทธ๋Œ€๋กœ ์‚ฝ์ž…
        if start == end:
            tree[index] = num_list[start]
            return tree[index]
        mid = (start + end) // 2
        # ์ขŒ์ธก ๋…ธ๋“œ์™€ ์šฐ์ธก ๋…ธ๋“œ ๊ฐ’์„ ๊ตฌํ•ด ๋ถ€๋ชจ ๋…ธ๋“œ์˜ ๊ฐ’์„ ํ•ฉ์ณ ๋งŒ๋“ ๋‹ค. (์ด๋•Œ ํ•ฉ์ด ์•„๋‹ˆ๋ผ ๊ตฌ๊ฐ„๊ณฑ์ด๋ฉด ๋ฐ”๊ฟ”์ฃผ์ž)
        tree[index] = create_recursive(
            start, mid, index * 2) + create_recursive(mid + 1, end, index * 2 + 1)
        return tree[index]
    create_recursive(0, len(num_list)-1)
    return tree

def interval_sum(tree, left, right, numCount):
    def sum_recursive(start, end, index=1):
        '''
        ์žฌ๊ท€๋ฅผ ํ†ตํ•œ ๊ตฌ๊ฐ„ํ•ฉ ๊ณ„์‚ฐ ํ•จ์ˆ˜
        index: ํ˜„์žฌ ์ฒ˜๋ฆฌ ์ค‘์ธ ์ธ๋ฑ์Šค
        start - end : ํ˜„์žฌ index ๋…ธ๋“œ๊ฐ€ ๊ฐ’์„ ์ €์žฅํ•œ ๊ตฌ๊ฐ„
        left, right : ๊ตฌ๊ฐ„ ํ•ฉ์„ ๊ตฌํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฒ”์œ„
        '''
        nonlocal tree, left, right  

        # ์›ํ•˜๋Š” ๊ตฌ๊ฐ„์ด tree ๋ฐ–์ธ ๊ฒฝ์šฐ
        if left > end or right < start:
            return 0  # ๊ณฑ์ผ ๊ฒฝ์šฐ ํ•ญ๋“ฑ์›์ธ 1 

        # ํ˜„์žฌ ์ธ๋ฑ์Šค๊ฐ€ ํฌํ•จํ•˜๋Š” ๊ตฌ๊ฐ„์ด ์ „๋ถ€ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ตฌ๊ฐ„ ์•ˆ์— ์žˆ๋Š” ๊ฒฝ์šฐ ๋”ํ•œ๋‹ค.
        if left <= start and right >= end:
            return tree[index]  

        # ์ผ๋ถ€๋งŒ ๊ฒน์นœ ๊ฒฝ์šฐ๋Š” ๋‘ ์ž์‹์œผ๋กœ ๋‚˜๋ˆ„์–ด ๊ตฌ๊ฐ„ ๋‚ด์— ์žˆ๋Š” ์ž์‹๋งŒ ๋”ํ•จ
        mid = (start + end) // 2
        return sum_recursive(start, mid, index * 2) + sum_recursive(mid + 1, end, index * 2 + 1)
    return sum_recursive(0, numCount-1)  

def update(tree, where, diff, numCount):
    def update_recursive(start, end, index=1):
        '''
        ํŠน์ • ์›์†Œ์˜ ๊ฐ’์„ ์ˆ˜์ •ํ•˜๋Š” ํ•จ์ˆ˜
        index : ํ˜„์žฌ ์ˆ˜์ • ํ•„์š” ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•˜๊ณ  ์žˆ๋Š” ํ•จ์ˆ˜
        start - end: index ๋…ธ๋“œ๊ฐ€ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š” ๋ฒ”์œ„
        where : ๊ตฌ๊ฐ„ ํ•ฉ์„ ์ˆ˜์ •ํ•˜๊ณ ์ž ํ•˜๋Š” ๋…ธ๋“œ
        value : ์ˆ˜์ •ํ•  ๊ฐ’
        '''
        nonlocal tree, where, diff
        # ๋ฒ”์œ„ ๋ฐ–์— ์žˆ๋Š” ๊ฒฝ์šฐ๋Š” ์•„๋ฌด๊ฒƒ๋„ ์•ˆํ•˜๊ณ  ์žฌ๊ท€ ์ค‘๋‹จ
        if where < start or where > end:
            return  

        # ๋ฒ”์œ„ ์•ˆ์— ์žˆ์œผ๋ฉด ๋‚ด๋ ค๊ฐ€๋ฉด์„œ ๋‹ค๋ฅธ ์›์†Œ๋„ ๊ฐฑ์‹ 
        tree[index] += diff
        if start != end:
            mid = (start + end) // 2
            update_recursive(start, mid, index*2)
            update_recursive(mid + 1, end, index*2+1)
    update_recursive(0, numCount-1)
    return tree  

# segment tree
{: #segment-tree}
numCount, changeCount, caseCount = map(int, input().split())
num_list = [0 for _ in range(numCount)]

for i in range(numCount):
    num_list[i] = int(input())
  
seg = create_seg_tree(num_list) 

for j in range(changeCount + caseCount):
    cmd, par1, par2 = map(int, input().split())
    if cmd == 1:
        loc, val = par1-1, par2
        seg = update(seg, loc, val - num_list[loc], numCount)
    elif cmd == 2:
        fr, to = par1-1, par2-1
        print(interval_sum(seg, fr, to, numCount))

์•„๋ž˜๋Š” ๋‹ค๋ฅธ ๋ฒ„์ „์˜ ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ์ด๋‹ค.
+ PROS
- ๋ฐ˜๋ณต๋ฌธ๊ณผ ๋น„ํŠธ ์—ฐ์‚ฐ์„ ํ™œ์šฉํ•ด ์ข€ ๋” ๋น ๋ฅด๋‹ค.
- ์ž๋ฃŒํ˜•์˜ ํฌ๊ธฐ๊ฐ€ ์ž…๋ ฅ ๊ฐ’์˜ 2๋ฐฐ๋กœ, ๋น„๊ต์  ํšจ์œจ์ ์ด๋‹ค.
- ์ž๋ฃŒํ˜•์— ๋ฐฐ์น˜๋œ ์›์†Œ๋“ค์ด ์œ„์น˜์ ์œผ๋กœ ์ง๊ด€์ ์ž„.
- ์œ„์น˜ n์˜ $n\times 2,\ n\times 2 + 1$์ด ์ž์‹์ด๋ฉฐ, ๋ฐ˜๋Œ€๋กœ $n//2$๋Š” ๋ถ€๋ชจ
- ์›์†Œ๋“ค์ด ์ธต ๋ณ„๋กœ ์ผ๋ ฌ๋กœ ๋ฐฐ์น˜๋จ.
- CONS
- ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ํž˜๋“ค๋‹ค. ํŠนํžˆ, left ์ธ๋ฑ์Šค์™€ right ์ธ๋ฑ์Šค์˜ ํ™œ์šฉ ๋ถ€๋ถ„
- ์ž๋ฃŒํ˜•์— ๋ฐฐ์น˜๋œ ์›์†Œ๋“ค์ด ์‹ค์ œ ์›๋ฆฌ์˜ ๋…ธ๋“œ์™€ ์กฐ๊ธˆ ๋‹ค๋ฅด๋‹ค.
- ์˜ˆ๋ฅผ ๋“ค์–ด, ์›์†Œ์˜ ๊ฐฏ์ˆ˜๊ฐ€ ํ™€์ˆ˜ ์ผ ๊ฒฝ์šฐ, ์„œ๋กœ ๋‹ค๋ฅธ ์ธต ๊ฐ’์˜ ํ•ฉ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ถ€๋ชจ ๋…ธ๋“œ๊ฐ€ ์ƒ๊น€.
- ๋”ฐ๋ผ์„œ lazy propagation ๊ตฌํ˜„์ด ํž˜๋“ค๊ณ  ๊ตฌํ˜„ํ•˜์ง€ ์•Š์„ ์‹œ, ๊ตฌ๊ฐ„ ์—…๋ฐ์ดํŠธ์— ์„ฑ๋Šฅ์ด ๋–จ์–ด์ง„๋‹ค.

๐Ÿงพ๏ธ ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ $O(\log n)$ ์˜ˆ์‹œ - ๋ฐ˜๋ณต ๋ฒ„์ „

# ๋ฐ˜๋ณต๋ฌธ์„ ์ด์šฉํ•œ ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ์ƒ์„ฑ
{: #๋ฐ˜๋ณต๋ฌธ์„-์ด์šฉํ•œ-์„ธ๊ทธ๋จผํŠธ-ํŠธ๋ฆฌ-์ƒ์„ฑ}
def create_tree(num_list):
    # ๋ถ€๋ชจ ๋…ธ๋“œ๋“ค์ด ๋“ค์–ด๊ฐˆ ๊ณต๊ฐ„ + ์›๋ณธ ๊ฐ’ ๊ณต๊ฐ„
    tree = [0 for _ in range(len(num_list))] + num_list # ํ•ญ๋“ฑ์› ์ฑ„์šฐ๊ธฐ
    # ๋ถ€๋ชจ ๋…ธ๋“œ ์ƒ์„ฑ 
    for i in range(len(num_list) - 1, 0, -1): # ๊ฑฐ๊พธ๋กœ ์‹œ์ž‘ํ•˜์—ฌ ๋ง๋‹จ ๋…ธ๋“œ์— ๊ฐ€๊นŒ์šด ๋ถ€๋ชจ๋ถ€ํ„ฐ ์ƒ์„ฑ
        tree[i] = tree[i << 1]+tree[i << 1 | 1] # ์—ฐ์‚ฐ ๋„ฃ๊ธฐ
    return tree  

# ๋ฐ˜๋ณต๋ฌธ์„ ์ด์šฉํ•œ ๊ตฌ๊ฐ„ํ•ฉ ๊ตฌํ•˜๊ธฐ
{: #๋ฐ˜๋ณต๋ฌธ์„-์ด์šฉํ•œ-๊ตฌ๊ฐ„ํ•ฉ-๊ตฌํ•˜๊ธฐ}
def interval_total(num_count, tree, left, right):
    # ์‹ค์ œ ๋ฒ”์œ„๋Š” ๋ถ€๋ชจ ๊ณต๊ฐ„์— ์˜ํ•ด ๋ฐ€๋ ค๋‚ฌ์œผ๋ฏ€๋กœ ๊ทธ๋งŒํผ ๋”ํ•ด์คŒ
    left += num_count
    right += num_count
    result = 0 # ํ•ญ๋“ฑ์›
    while (left <= right):
        # ์ธ๋ฑ์Šค์˜ ํ™€์ˆ˜ ์ง์ˆ˜ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๋‘๊ฐ€์ง€๋กœ ๋‚˜๋‰œ๋‹ค.
        # 1. ์ด ๋…ธ๋“œ์˜ ๊ฐ’์„ ํฌํ•จํ•œ ๋ถ€๋ชจ ๋…ธ๋“œ๊ฐ€ ์žˆ์Œ(=๋”ํ•˜์ง€ ์•Š์Œ)
        # 2. ์ด ๋…ธ๋“œ์˜ ๊ฐ’์„ ํฌํ•จํ•œ ๋…ธ๋“œ๊ฐ€ ์—†์Œ (=๋”ํ•ด์ค˜์•ผ ํ•จ)
        if (left & 1):  # ์™ผ์ชฝ ์ธ๋ฑ์Šค๊ฐ€ ํ™€์ˆ˜์ด๋ฉด
            result += tree[left]  # ํ•ด๋‹น ๊ฐ’์„ ์—ฐ์‚ฐ
            left += 1  # ์ธ๋ฑ์Šค ์ฆ๊ฐ€
        if not (right & 1):  # ์˜ค๋ฅธ์ชฝ ์ธ๋ฑ์Šค๊ฐ€ ์ง์ˆ˜์ด๋ฉด
            result += tree[right]  # ํ•ด๋‹น ๊ฐ’์„ ์—ฐ์‚ฐ
            right -= 1  # ์ธ๋ฑ์Šค ๊ฐ
        # ์ธ๋ฑ์Šค๋ฅผ ์ ˆ๋ฐ˜์œผ๋กœ ์ค„์ž„ == ํ•ด๋‹น ๊ฐ’์˜ ๋ถ€๋ชจ ๋…ธ๋“œ๋กœ
        left >>= 1
        right >>= 1
    return result

# ๋ฐ˜๋ณต๋ฌธ์„ ์ด์šฉํ•œ ํŠธ๋ฆฌ ๊ฐฑ์‹ 
{: #๋ฐ˜๋ณต๋ฌธ์„-์ด์šฉํ•œ-ํŠธ๋ฆฌ-๊ฐฑ์‹ }
def update(tree, index, val, num_count):
    index += num_count
    tree[index] = val
    # ๋ถ€๋ชจ ๋…ธ๋“œ ์—…๋ฐ์ดํŠธ
    while index > 1:
        tree[index >> 1] = tree[index] + tree[index ^ 1] # ์—ฐ์‚ฐ 
        index >>= 1
    return tree
    
# segment tree
{: #segment-tree}
numCount, changeCount, caseCount = map(int, input().split())  

arr = [0 for _ in range(numCount)]

for i in range(numCount):
    arr[i] = int(input())  

seg = create_tree(arr) 

for j in range(changeCount + caseCount):
    cmd, par1, par2 = map(int, input().split())
    if cmd == 1:
        loc, val = par1-1, par2
        update(seg, loc, val, numCount)
    elif cmd == 2:
        fr, to = par1-1, par2-1
        print(interval_total(numCount, seg, fr, to))
๐Ÿงพ๏ธ ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ์ž๋ฐ” ๋ฒ„์ „
class SegmentTree {
    private long[] tree;
    private int n;  

    public SegmentTree(long[] nums) {
        n = nums.length;
        tree = new long[4 * n]; // use 4 * n for a balanced tree

        buildTree(nums, 1, 0, n - 1);
    }
    // builds the segment tree recursively
    private void buildTree(long[] nums, int node, int start, int end) {
        if (start == end) {
            tree[node] = nums[start];
        } else {
            int mid = (start + end) / 2;
            int leftChild = 2 * node, rightChild = 2 * node + 1;

            buildTree(nums, leftChild, start, mid);
            buildTree(nums, rightChild, mid + 1, end); 

            // combine the results of the left and right subtrees
            tree[node] = tree[leftChild] + tree[rightChild];
        }
    }

    // updates the value at index i to val
    public void update(int i, long val) {
        updateTree(1, 0, n - 1, i, val);
    } 

    // updates the segment tree recursively
    private void updateTree(int node, int start, int end, int i, long val) {
        if (start == end) {
            tree[node] = val;
        } else {
            int mid = (start + end) / 2;
            int leftChild = 2 * node, rightChild = 2 * node + 1;  

            if (i <= mid) {
                updateTree(leftChild, start, mid, i, val);
            } else {
                updateTree(rightChild, mid + 1, end, i, val);
            }  

            // combine the results of the left and right subtrees
            tree[node] = tree[leftChild] + tree[rightChild];
        }
    }

    // returns the sum of the values in the range [i, j]
    public long sumRange(int i, int j) {
        return queryTree(1, 0, n - 1, i, j);
    }

    // queries the segment tree recursively
    private long queryTree(int node, int start, int end, int i, int j) {
        if (j < start || i > end) {
            return 0;
        } else if (i <= start && j >= end) {
            return tree[node];
        } else {
            int mid = (start + end) / 2;
            int leftChild = 2 * node, rightChild = 2 * node + 1;
            return queryTree(leftChild, start, mid, i, j) + queryTree(rightChild, mid + 1, end, i, j);
        }
    }
}

๋™์  ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ(Dynamic segment tree)

๐Ÿงพ๏ธ ๋™์  ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ์˜ˆ์‹œ

์ง€์† ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ(Persistent segment tree)

๐Ÿงพ๏ธ ์ง€์† ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ์˜ˆ์‹œ

๋‹ค์ฐจ์› ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ (multi dimensional segment tree)

๐Ÿงพ๏ธ ๋‹ค์ฐจ์› ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ์˜ˆ์‹œ

๊ฒŒ์œผ๋ฅธ ์ „ํŒŒ ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ (segment tree with lazy propagation)

  • ํ•˜๋‹จ ์ฝ”๋“œ๋Š” ์ดํ•ด๋ฅผ ๋•๊ธฐ ์œ„ํ•ด dictionary๋ฅผ ํ™œ์šฉํ–ˆ์œผ๋ฉฐ, ์‹ค์ œ๋กœ ์•„๋ž˜ ์ฝ”๋“œ๋Š” ํ•„์š”ํ•œ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์–ด๋งˆ์–ด๋งˆํ•˜๋ฏ€๋กœ, ๋‹ค์ฐจ์› ๋ฐฐ์—ด์ด๋‚˜ lazy์™€ value๋ฅผ ๋‹ค๋ฅธ ๋ฐฐ์—ด๋กœ ๋‚˜๋ˆ„์ž.
๐Ÿงพ๏ธ ๊ฒŒ์œผ๋ฅธ ์ „ํŒŒ ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ์˜ˆ์‹œ
import sys
import math
input = sys.stdin.readline 

def createSegTreeLazy(nums):
    # ํ•„์š”ํ•œ ๋…ธ๋“œ ์ˆ˜ == ์žŽ์ƒˆ ๋…ธ๋“œ(N) + ๋ถ€๋ชจ ๋…ธ๋“œ(N-1) == 2N - 1
    # ๋”ฐ๋ผ์„œ ๋†’์ด๋ฅผ H๋ผ๊ณ  ๋†“์„ ๋•Œ โˆ‘^{H}_{n=0}2^n >= 2N -1์„ ๋งŒ์กฑํ•ด์•ผ ํ•œ๋‹ค.
    # tree์˜ ํฌ๊ธฐ๋Š” 2์˜ (์˜ˆ์ƒ ํŠธ๋ฆฌ์˜ ๋†’์ด + 1)์Šน์ด๋ฉด ์ ˆ๋Œ€ ๋ถ€์กฑํ•˜์ง€ ์•Š๋‹ค.
    # 0: ํ•ญ๋“ฑ์›, 1: lazy, ๊ธฐ๋ณธ 0
    tree = [[0,0] for _ in range(1 << (math.ceil(math.log2(len(nums)))+1))]  
    
    def createWithRecur(start, end, index=1):
        nonlocal tree
        if start == end:
            tree[index][0] = nums[start]
        else:
            mid = (start + end) // 2
            createWithRecur(start, mid, index * 2)
            createWithRecur(mid + 1, end, index * 2 + 1)
            tree[index][0] = tree[index*2][0] + tree[index*2 + 1][0]
    createWithRecur(0, len(nums)-1)
    return tree

  

def propagation(tree, where, start, end):
    '''
    lazy๊ฐ’์ด ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ๊ฐ’์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์ž์‹ ๋…ธ๋“œ๋กœ lazy ๊ฐ’์„ ์ „ํŒŒํ•˜๋Š” ํ•จ์ˆ˜
    '''
    if start != end:
        tree[where * 2][1] += tree[where][1]
        tree[where * 2 + 1][1] += tree[where][1]
    tree[where][0] += tree[where][1] * (end - start + 1) 

    tree[where][1] = 0
    return tree 

def intervalUpdateLazy(tree, numCount, left, right, diff):
    '''
    lazy ๊ตฌ๊ฐ„ ์—…๋ฐ์ดํŠธ ๊ตฌํ•˜๊ธฐ
    left, right : ์ˆ˜์ •ํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฒ”์œ„
    start, end : ํ˜„์žฌ ๊ณ„์‚ฐ ์ค‘์ธ ๋ฒ”์œ„(ํ˜„์žฌ index๋ฒˆ์˜ ๋…ธ๋“œ๊ฐ€ ์ปค๋ฒ„ํ•˜๋Š” ๊ณต๊ฐ„)
    index : ํ˜„์žฌ updateํ•˜๋Š” ๋…ธ๋“œ
    diff : ๋ณ€ํ™”๋˜๋Š” ๊ฐ’
    '''
    def updateWithRecur(start, end, index=1):
        nonlocal tree, left, right, diff
        if tree[index][1]:  # ์ด์ „์— ์Œ“์€ lazy๊ฐ’์ด ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ์ˆ˜์ • ๋’ค lazy ์ „ํŒŒ
            tree = propagation(tree, index, start, end)
        if end < left or right < start:  # ๊ตฌํ•˜๋Š” ๊ตฌ๊ฐ„์ด ๊ด€๊ณ„ ์—†๋Š” ๊ฒฝ์šฐ
            return
        if left <= start and end <= right:  # ํ•ด๋‹น ๋…ธ๋“œ๊ฐ€ ์ปค๋ฒ„ํ•˜๋Š” ๊ตฌ๊ฐ„์ด ์™„์ „ํžˆ ํฌํ•จ๋  ๊ฒฝ์šฐ
            tree[index][0] += (end - start + 1) * diff
            if start != end:  # ๋ง๋‹จ ๋…ธ๋“œ๊ฐ€ ์•„๋‹ ๊ฒฝ์šฐ,
                tree[index * 2][1] += diff
                tree[index * 2 + 1][1] += diff
            return
        else:
            mid = (start + end) // 2
            updateWithRecur(start, mid, index*2)
            updateWithRecur(mid + 1, end, index*2 + 1)
            tree[index][0] = tree[index*2][0] + tree[index*2+1][0]
    updateWithRecur(0, numCount-1)
    return tree

def intervalSumLazy(tree, numCount, left, right):
    def getWithRecur(start, end, index=1):
        '''
        lazy ๊ตฌ๊ฐ„ ํ•ฉ ๊ตฌํ•˜๊ธฐ
        index : ํ˜„์žฌ ์ฒ˜๋ฆฌ ์ค‘์ธ ๋…ธ๋“œ์˜ ์ธ๋ฑ์Šค
        start, end : ํ˜„์žฌ ์ฒ˜๋ฆฌ ์ค‘์ธ ์ธ๋ฑ์Šค ๋…ธ๋“œ๊ฐ€ ๊ฐ’์„ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š” ๋ฒ”์œ„
        left, right : ๊ฐ’์„ ๊ตฌํ•  ๋ฒ”์œ„
        '''
        nonlocal tree, left, right
        if tree[index][1]:
            tree = propagation(tree, index, start, end) 
        if end < left or right < start:
            return 0
        if left <= start and end <= right:
            return tree[index][0]
        else:
            mid = (start+end)//2
            return getWithRecur(start, mid, index*2) + getWithRecur(mid + 1, end, index * 2 + 1)
    return getWithRecur(0, numCount-1)  

numCount, chngCount, sumCount = map(int, input().split())
number_list = [int(input()) for _ in range(numCount)]
tree = createSegTreeLazy(number_list) 

for i in range(chngCount + sumCount):
    cmds = list(map(int, input().split()))
    if cmds[0] == 1:
        _, fr, to, chng = cmds
        intervalUpdateLazy(tree, numCount, fr-1, to-1, chng)
    elif cmds[1] == 2:
        _, fr, to = cmds
        print(intervalSumLazy(tree, numCount, fr-1, to-1))

BIT (Binary Indexed Tree, ํŽœ์œ… ํŠธ๋ฆฌ, fenwick tree)

๐Ÿงพ๏ธ BIT ์˜ˆ์‹œ

ํŠธ๋ผ์ด(Trie)

์ฃผ๋กœ ๋ฌธ์ž์—ด๊ณผ ๊ด€๋ จ๋˜์–ด ์‚ฌ์šฉ๋˜๋‚˜, ํŠธ๋ฆฌ๋ฅผ ์ด์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ณณ์— ํŽธ์ž…

n์ง„ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ์ด์šฉํ•ด ์ฐพ๊ณ ์ž ํ•˜๋Š” ๊ฒ€์ƒ‰ํ•  ๋ฌธ์ž์—ด์˜ ๊ธธ์ด๋ฅผ $M$์ด๋ผ ํ•  ๋•Œ, $O(M)$์ด ๋œ๋‹ค.

๐Ÿงพ๏ธ Trie ์˜ˆ์‹œ
class Trie:
    def __init__(self, value):
        self.value = value
        self.childs = {} 

    def insert(self, word):
        currNode = self
        for letter in word:
            if currNode.childs.get(letter):
                currNode.childs[letter].value += 1
            else:
                currNode.childs[letter] = Trie(1)
            currNode = currNode.childs[letter]

    def search(self, query):
        currNode = self
        for i, letter in enumerate(query):
            if currNode.childs.get(letter):
                currNode = currNode.childs[letter]
            else:
                return 0
        if i == len(query) - 1:
            return currNode.value        

def solution(
    words, queries
):
    trie = Trie(0)
    for word in words:
        trie.insert(word)
    result = [trie.search(query) for query in queries]
    return result