본문 바로가기

트리/세그먼트 트리

Lazy propagation

구간을 업데이트할 때 사용

vector<ll> lazy;

배열을 하나 만들어준다.

 

update_lazy() 함수

lazy[node] 값이 있다면

tree[node] += (end - start + 1) * lazy[node]; 해준다.

start != end이면

lazy propagation 하고,

비워준다.

lazy[node] = 0;

 

1. update_range() 함수

update_lazy() 함수 호출

 

a) 변경 범위가 탐색 구간에 없음

return;

 

b) 변경 범위가 탐색 구간 안에 있음

tree[node] += (end - start + 1) * diff;

하고

start != end이면

lazy[node*2], lazy[node*2 + 1]에 += diff 해준다.

 

c) 변경 범위 중 하나만 탐색 구간에 있음 -> Top-down

 

2. query

똑같다. 단지 update_lazy() 함수 호출이 제일 처음에 호출된다.

 

https://www.acmicpc.net/problem/10999

 

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

<소스코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <iostream>
#include <cmath>
#include <vector>
 
using namespace std;
 
typedef long long ll;
 
vector<ll> arr;
vector<ll> tree;
vector<ll> lazy;
 
void init(int node, int start, int end)
{
    if (start == end)
        tree[node] = arr[start];
    else
    {
        int mid = start + (end - start) / 2;
        init(node * 2, start, mid);
        init(node * 2 + 1, mid + 1end);
        tree[node] = tree[node * 2+ tree[node * 2 + 1];
    }
}
 
void update_lazy(int node, int start, int end)
{
    if (lazy[node] != 0)
    {
        tree[node] += (end - start + 1* lazy[node];
        
        //lazy propagation
        if (start != end)
        {
            lazy[node * 2+= lazy[node];
            lazy[node * 2 + 1+= lazy[node];
        }
        lazy[node] = 0;
    }
}
 
void update_range(int node, int start, int endint left, int right, long long diff)
{
    update_lazy(node, start, end);
 
    // 변경 idx 범위가 탐색 구간에 없음
    if (left > end || right < start)
        return;
 
    //  둘 다 변경 범위에 있음
    if (left <= start && end <= right)
    {
        tree[node] += (end - start + 1* diff;
        if (start != end)
        {
            lazy[node * 2+= diff;
            lazy[node * 2 + 1+= diff;
        }
        return;
    }
 
    // 하나만 변경 범위에 있음
    int mid = start + (end - start) / 2;
    update_range(node * 2, start, mid, left, right, diff);
    update_range(node * 2 + 1, mid + 1end, left, right, diff);
    tree[node] = tree[node * 2+ tree[node * 2 + 1];
}
 
ll query(int node, int start, int endint left, int right)
{
    update_lazy(node, start, end);
 
    if (left > end || right < start)
        return 0;
 
    if (left <= start && end <= right)
        return tree[node];
 
    int mid = start + (end - start) / 2;
    ll lsum = query(node * 2, start, mid, left, right);
    ll rsum = query(node * 2 + 1, mid + 1end, left, right);
    return lsum + rsum;
}
 
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    int n, m, k;
    cin >> n >> m >> k;
 
    arr.resize(n);
 
    for (int i = 0; i < n; i++)
        cin >> arr[i];
    
    int h = (int)ceil(log2(n));
    int tree_size = (1 << (h + 1));
    tree.resize(tree_size);
    lazy.resize(tree_size);
 
    init(10, n - 1);
    m += k;
 
    while (m--)
    {
        int which;
        cin >> which;
        if (which == 1)
        {
            int left, right;
            long long diff;
            cin >> left >> right >> diff;
            update_range(10, n - 1, left - 1, right - 1, diff);
        }
        else if (which == 2)
        {
            int left, right;
            cin >> left >> right;
            cout << query(10, n - 1, left - 1, right - 1<< '\n';
        }
    }
    return 0;
}
 
cs

'트리 > 세그먼트 트리' 카테고리의 다른 글

히스토그램에서 가장 큰 직사각형  (1) 2024.02.20
블록쌓기게임  (0) 2024.02.19
출근길 라디오  (0) 2024.02.13
Top-down 세그먼트 트리  (0) 2024.02.13
구간 곱 구하기  (1) 2024.01.13