백준의 구간합 구하기2(10999) 문제이다.

[ 문제 바로가기 ]


[ 문제풀이 ]

먼저 문제를 보면 구간에 대한 합을 구하는 문제이다. 구간에 대한 연산은 "세그먼트 트리" 혹은 "펜윅트리"를 이용해서 빠르고 효율적으로 해결할 수 있다.

본인은 세그먼트 트리로 이 문제에 접근해보았는데 아직 세그먼트 트리에 대해서 잘 모른다면 아래의 글을 읽고 오도록 하자.

[ 세그먼트 트리 알아보기(Click) ]


그런데 ! 이 문제는 단순 세그먼트 트리를 이용해서 구현한다면 시간초과가 발생하게 된다. 왜냐하면 값을 업데이트 하는 것 또한 구간의 개념으로 주어지기 때문에, 제 시간 내에 연산을 다 할 수가 없다. 그래서 'Lazy Propagation' 방식을 이용해서 구현해주어야 한다. 아직 Lazy Propagation에 대해서 잘 모른다면 아래의 글을 읽고 오도록 하자.

[ Lazy Propagation 알아보기 (Click) ]


위에 링크를 걸어놓은 세그먼트 트리에 대한 설명과, Lazy Propagation 설명에 대한 글 만으로도 이 문제의 풀이를 충분히 대체할 수 있기 때문에 별다른 추가적인 설명은 진행하지 않겠다.


[ 소스코드 ]

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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include<iostream>
#include<vector>
#include<cmath>
 
#define endl "\n"
#define MAX 1000010
typedef long long ll;
using namespace std;
 
int N, M, K;
int Arr[MAX];
vector<ll> Lazy;
vector<ll> SegmentTree;
vector<pair<pair<intint>pair<intint>>> Cmd;
 
void Input()
{
    cin >> N >> M >> K;
    for (int i = 0; i < N; i++cin >> Arr[i];
    for (int i = 0; i < M + K; i++)
    {
        int a; cin >> a;
        if (a == 1)
        {
            int b, c, d; cin >> b >> c >> d;
            Cmd.push_back(make_pair(make_pair(a, b), make_pair(c, d)));
        }
        else
        {
            int b, c; cin >> b >> c;
            Cmd.push_back(make_pair(make_pair(a, b), make_pair(c, -1)));
        }
    }
}
 
ll Make_SegmentTree(int Node, int Start, int End)
{
    if (Start == End) return SegmentTree[Node] = Arr[Start];
 
    int Mid = (Start + End) / 2;
    ll Left_Result = Make_SegmentTree(Node * 2, Start, Mid);
    ll Right_Result = Make_SegmentTree(Node * 2 + 1, Mid + 1, End);
    SegmentTree[Node] = Left_Result + Right_Result;
 
    return SegmentTree[Node];
}
 
void Setting_SegmentTree()
{
    int Tree_Height = (int)ceil(log2(N));
    int Tree_Size = (1 << (Tree_Height + 1));
    SegmentTree.resize(Tree_Size);
    Lazy.resize(Tree_Size);
    Make_SegmentTree(10, N - 1);
}
 
void Lazy_Update(int Node, int Start, int End)
{
    if (Lazy[Node] != 0)
    {
        SegmentTree[Node] = SegmentTree[Node] + (End - Start + 1* Lazy[Node];
        if (Start != End)
        {
            Lazy[Node * 2= Lazy[Node * 2+ Lazy[Node];
            Lazy[Node * 2 + 1= Lazy[Node * 2 + 1+ Lazy[Node];
        }
        Lazy[Node] = 0;
    }
}
 
void Update(int Node, int Start, int End, int Left, int Right, ll Value)
{
    Lazy_Update(Node, Start, End);
    if (Right < Start || Left > End) return;
    if (Left <= Start && End <= Right)
    {
        SegmentTree[Node] = SegmentTree[Node] + (End - Start + 1* Value;
        if (Start != End)
        {
            Lazy[Node * 2= Lazy[Node * 2+ Value;
            Lazy[Node * 2 + 1= Lazy[Node * 2 + 1+ Value;
        }
        return;
    }
 
    int Mid = (Start + End) / 2;
    Update(Node * 2, Start, Mid, Left, Right, Value);
    Update(Node * 2 + 1, Mid + 1, End, Left, Right, Value);
    SegmentTree[Node] = SegmentTree[Node * 2+ SegmentTree[Node * 2 + 1];
}
 
ll Query(int Node, int Start, int End, int Left, int Right)
{
    Lazy_Update(Node, Start, End);
    if (Right < Start || Left > End) return 0;
    if (Left <= Start && End <= Right) return SegmentTree[Node];
 
    int Mid = (Start + End) / 2;
    ll Left_Result = Query(Node * 2, Start, Mid, Left, Right);
    ll Right_Result = Query(Node * 2 + 1, Mid + 1, End, Left, Right);
    return Left_Result + Right_Result;
}
 
void Solution()
{
    Setting_SegmentTree();
    for (int i = 0; i < M + K; i++)
    {
        int Command = Cmd[i].first.first;
        if (Command == 1)
        {
            int Index = Cmd[i].first.second - 1;
            int Index2 = Cmd[i].second.first - 1;
            ll Value = Cmd[i].second.second;
 
            Update(10, N - 1, Index, Index2, Value);
        }
        else
        {
            int Index = Cmd[i].first.second - 1;
            int Index2 = Cmd[i].second.first - 1;
            cout << Query(10, N - 1, Index, Index2) << endl;
        }
    }
}
 
void Solve()
{
    Input();
    Solution();
}
 
int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    //freopen("Input.txt", "r", stdin);
    Solve();
 
    return 0;
}
cs


+ Recent posts