SlideShare a Scribd company logo
#1—
세그먼트트리느리게업데이트하기
Lazy Propagation on Segment Trees
by
Suhyun Park
Sogang ICPC Team – 2020 겨울 고급 스터디 acm.sogang.ac.kr
환영합니다!
Sogang ICPC Team 1
“고급” 스터디에 오신 여러분을 환영합니다!
환영합니다!
Sogang ICPC Team 2
저는...
✓ 박수현 – @shiftpsh / shiftpsh.com
✓ Sogang ICPC Team 전임 학회장 – 2019년
✓ ICPC 2019 Seoul Regional에 팀 Redshift로 참가 – 8위
✓ solved.ac를 만든 사람!
“고급” 스터디를 시작하기 전에...
Sogang ICPC Team 3
“고급” 스터디는 초급이나 중급 스터디와는 진행방식이 좀 다릅니다
✓ 옆 동네에서 하는 팀 빌딩이나 모의고사 등 재밌는 것들 → 없어요
✓ 기본적으로 혼자 열심히 하셔야 해요
– 여기 오실 정도의 여러분들이 PS에 미친 분들이라는 건 확실해 보이니 걱정하지
않겠습니다
“고급” 스터디를 시작하기 전에...
Sogang ICPC Team 4
다루게 되는 것들
✓ solved.ac 기준으로 에서 사이의 문제들
✓ 실무에서는 전혀 쓸 것 같지 않고 실제로도 별로 안 쓰이는 생소한 알고리즘과
자료구조들
– 하지만 대회에서는 나온다
✓ 여하튼 ICPC 등의 “대회 준비”에 초점이 맞춰져 있습니다
“고급” 스터디를 시작하기 전에...
Sogang ICPC Team 5
“고급”에 붙어 있는 따옴표는 뭐에요?
✓ 고급 스터디에서 다루는 자료구조와 알고리즘들은 대회 준비의 필요조건이지
충분조건이 아닙니다
– 이런 거 많이 아는 것보다 이미 아는 알고리즘을 잘 써먹는 방법을 공부하는 게
대회 성적에 훨씬 도움이 됩니다
✓ 진짜 “고급” – 이미 알고 있는 알고리즘들을 잘 써먹는 능력을 기르는 스터디
– 팀 연습 등
“고급” 스터디를 시작하기 전에...
Sogang ICPC Team 6
그럼 이거 왜 하는 거에요?
✓ 모르면 아예 못 푸는 내용들을 대비하기 위해
✓ 남들한테는 다 웰노운인데 나한테만 아닌 것들을 나에게도 웰노운으로 만들어 써먹기
위해
– 팀노트에 적어가세요
✓ solved.ac 경험치 올리기 위해
Remarks on Segment Trees
Sogang ICPC Team 7
1–10
1–5 6–10
1–3 4–5 6–8 9–10
1–2 3 4 5 6–7 8 9 10
1 2 6 7
f (x, s, e, · · · ) = f
(
2x, s,
⌊
s + e
2
⌋
, · · ·
)
+ f
(
2x + 1,
⌊
s + e
2
⌋
+ 1, e, · · ·
)
Remarks on Segment Trees
Sogang ICPC Team 8
1–10
1–5 6–10
1–3 4–5 6–8 9–10
1–2 3 4 5 6–7 8 9 10
1 2 6 7
A5 · · · A9 의 합?
Remarks on Segment Trees
Sogang ICPC Team 9
✓ Al · · · Ar 의 합 쿼리 = O (log n)
✓ Ai 업데이트 = O (log n)
Lazy Propagation
Sogang ICPC Team 10
✓ Al · · · Ar 의 합 쿼리
✓ Al · · · Ar 업데이트
의 두 쿼리를 처리해야 한다고 생각해 보자
– 하나하나 업데이트한다면 쿼리 한 번에 O ((r − l) log n) → 사실상 O (n log n)
Lazy Propagation
Sogang ICPC Team 11
쿼리 한 번에 O (n log n)은 느려도 너무 느리다
→ 업데이트할 때 매번 리프 노드까지 보내지 말자
→ 트리를 하나 더 만들어서 거기다 업데이트하고 쿼리할 때 한꺼번에 업데이트하자
Lazy Propagation
Sogang ICPC Team 12
40 ll a[1000001], tree[1048576 * 2], lazy[1048576 * 2];
41
42 void _propagate(int x, int s, int e) {
43 if (!lazy[x]) return;
44 tree[x] += (e - s + 1) * lazy[x];
45 if (s != e) {
46 lazy[x * 2] += lazy[x];
47 lazy[x * 2 + 1] += lazy[x];
48 }
49 lazy[x] = 0;
50 }
lazy라는 이름으로 별도의 트리를 만든다
Lazy Propagation
Sogang ICPC Team 13
40 ll a[1000001], tree[1048576 * 2], lazy[1048576 * 2];
41
42 void _propagate(int x, int s, int e) {
43 if (!lazy[x]) return;
44 tree[x] += (e - s + 1) * lazy[x];
45 if (s != e) {
46 lazy[x * 2] += lazy[x];
47 lazy[x * 2 + 1] += lazy[x];
48 }
49 lazy[x] = 0;
50 }
노드 x에 아직 업데이트하지 않은 값이 있다면 트리에 업데이트해주는 메서드
Lazy Propagation
Sogang ICPC Team 14
52 ll _sum(int x, int s, int e, int l, int r) {
53 _propagate(x, s, e);
54 if (l > e || r < s) return 0;
55 if (l <= s && e <= r) return tree[x];
56 int m = (s + e) / 2;
57 return _sum(x * 2 , s, m, l, r) +
58 _sum(x * 2 + 1, m + 1, e, l, r);
59 }
합 쿼리를 계산할 때 propagation을 해 줘야 한다
Lazy Propagation
Sogang ICPC Team 15
61 void _update(int x, int s, int e, int l, int r, ll dv) {
62 _propagate(x, s, e);
63 if (l > e || r < s) return;
64 if (l <= s && e <= r) {
65 tree[x] += (e - s + 1) * dv;
66 if (s != e) {
67 lazy[x * 2] += dv;
68 lazy[x * 2 + 1] += dv;
69 }
70 return;
71 }
72 int m = (s + e) / 2;
73 _update(x * 2 , s, m, l, r, dv);
74 _update(x * 2 + 1, m + 1, e, l, r, dv);
75 tree[x] = tree[x * 2] + tree[x * 2 + 1];
76 }
업데이트할 때도 propagation을 해 줘야 한다
Lazy Propagation
Sogang ICPC Team 16
61 void _update(int x, int s, int e, int l, int r, ll dv) {
62 _propagate(x, s, e);
63 if (l > e || r < s) return;
64 if (l <= s && e <= r) {
65 tree[x] += (e - s + 1) * dv;
66 if (s != e) {
67 lazy[x * 2] += dv;
68 lazy[x * 2 + 1] += dv;
69 }
70 return;
71 }
72 int m = (s + e) / 2;
73 _update(x * 2 , s, m, l, r, dv);
74 _update(x * 2 + 1, m + 1, e, l, r, dv);
75 tree[x] = tree[x * 2] + tree[x * 2 + 1];
76 }
현재 확인하는 구간이 업데이트 구간 안에 있다면 리프 노드까지 가지 않고 lazy를
업데이트하고 끝낸다
Lazy Propagation
Sogang ICPC Team 17
89 ll sum(int l, int r) {
90 return _sum(1, 1, 1000000, l, r);
91 }
92
93 void update(int l, int r, ll dv) {
94 _update(1, 1, 1000000, l, r, dv);
95 }
96
97 void initialize() {
98 _initialize(1, 1, 1000000);
99 }
_initialize는 세그먼트 트리의 그것과 같으므로 생략
구간 합 구하기 2 #
10999
Sogang ICPC Team 18
✓ n ≤ 106
✓ m + k ≤ 20000
구현해보자
구간 합 구하기 2 #
10999
Sogang ICPC Team 19
115 while (q--) {
116 int op, l, r;
117 cin >> op >> l >> r;
118 if (op == 1) {
119 ll dv;
120 cin >> dv;
121 update(l, r, dv);
122 } else { // op == 2
123 cout << sum(l, r) << 'n';
124 }
125 }
source code
JuQueen #
10277
Sogang ICPC Team 20
코어가 4, 587, 520개인 컴퓨터의 클럭을 변경하는 프로그램을 짜야 한다. N 단계의 클럭이
가능하고
✓ CPU x의 클럭을 s단계만큼 증감
✓ CPU a · · · b의 클럭을 s단계만큼 증감
✓ CPU x의 클럭 단계 출력
중 하나를 할 수 있다.
클럭은 한 단계씩만 올라가거나 내려가며, 여러 코어에 대해 여러 단계를 한꺼번에 증감할
경우 그 중 하나라도 0단계나 N 단계에 도달하면 증감을 종료하고 증감한 만큼의 단계를
출력한다.
JuQueen #
10277
Sogang ICPC Team 21
클럭은 한 단계씩만 올라가거나 내려가며, 여러 코어에 대해 여러 단계를 한꺼번에 증감할
경우 그 중 하나라도 0단계나 N 단계에 도달하면 증감을 종료하고 증감한 만큼의 단계를
출력한다.
✓ 지금 클럭들이 1, 2, 3, 4고 N = 6이라면, 클럭 4단계를 올리라는 명령을 내린다면 2
단계만 올라가고 끝난다
JuQueen #
10277
Sogang ICPC Team 22
CPU a · · · b의 클럭 단계의 최솟값을 mn, 최댓값을 mx라 하고, s만큼 증감하고자 한다면
✓ mx + s > N 이라면? N − mx만큼만 올릴 수 있다
✓ mn + s < 0이라면? mn만큼만 내릴 수 있다
✓ 둘 다 아니라면 s만큼 올릴 수 있다
JuQueen #
10277
Sogang ICPC Team 23
세 가지 연산을 할 수 있는 자료구조가 필요
✓ 인덱스 l · · · r에서의 최솟값 구하기
✓ 인덱스 l · · · r에서의 최댓값 구하기
✓ 인덱스 l · · · r을 전부 s만큼 증가시키기
하나의 원소 i에 대해서만 연산할 경우 l = r = i
JuQueen #
10277
Sogang ICPC Team 24
A = {a0, a1, · · · , an}
A′
= {a0 + d, a1 + d, · · · , an + d}
이라고 하면
max
a′∈A′
(
a′
)
= max
a∈A
(a) + d
min
a′∈A′
(
a′
)
= min
a∈A
(a) + d
이 성립 → 그냥 더해주면 된다. 별 문제 없다
JuQueen #
10277
Sogang ICPC Team 25
✓ 인덱스 l · · · r에서의 최솟값 구하기
✓ 인덱스 l · · · r에서의 최댓값 구하기
· · · 를 하기 위해 세그먼트 트리를 튜플 ⟨min, max⟩ 로 만들고
✓ 인덱스 l · · · r을 전부 s만큼 증가시키기
· · · 를 하기 위해 lazy propagate 하면 되겠다!
JuQueen #
10277
Sogang ICPC Team 26
40 struct mii {
41 ll mn, mx;
42 };
43
44 mii tree[8388608 * 2];
45 int lazy[8388608 * 2];
46
47 int inf = 987654321;
48 int c, n, o;
source code
first, second는 헷갈리니까 struct를 새로 만든다. 어차피 정렬할 것도 아닌데· · ·
JuQueen #
10277
Sogang ICPC Team 27
50 void _propagate(int x, int s, int e) {
51 if (!lazy[x]) return;
52 tree[x].mn += lazy[x];
53 tree[x].mx += lazy[x];
54 if (s != e) {
55 lazy[x * 2] += lazy[x];
56 lazy[x * 2 + 1] += lazy[x];
57 }
58 lazy[x] = 0;
59 }
source code
Propagation – 더해주는 쿼리를 처리해 주기 위함
JuQueen #
10277
Sogang ICPC Team 28
61 ll _minimum(int x, int s, int e, int l, int r) {
62 _propagate(x, s, e);
63 if (l > e || r < s) return inf;
64 if (l <= s && e <= r) return tree[x].mn;
65 int m = (s + e) / 2;
66 return min(_minimum(x * 2, s, m, l, r),
67 _minimum(x * 2 + 1, m + 1, e, l, r));
68 }
source code
구간 최솟값 쿼리를 처리하면서 propagation도 같이 한다
JuQueen #
10277
Sogang ICPC Team 29
70 ll _maximum(int x, int s, int e, int l, int r) {
71 _propagate(x, s, e);
72 if (l > e || r < s) return 0;
73 if (l <= s && e <= r) return tree[x].mx;
74 int m = (s + e) / 2;
75 return max(_maximum(x * 2, s, m, l, r),
76 _maximum(x * 2 + 1, m + 1, e, l, r));
77 }
source code
최댓값에 대해서도 동일하게 처리해 준다
JuQueen #
10277
Sogang ICPC Team 30
79 void _update(int x, int s, int e, int l, int r, ll dv) {
80 _propagate(x, s, e);
81 if (l > e || r < s) return;
82 if (l <= s && e <= r) {
83 tree[x].mn += dv;
84 tree[x].mx += dv;
85 if (s != e) {
86 lazy[x * 2] += dv;
87 lazy[x * 2 + 1] += dv;
88 }
89 return;
90 }
91 int m = (s + e) / 2;
92 _update(x * 2 , s, m, l, r, dv);
93 _update(x * 2 + 1, m + 1, e, l, r, dv);
94 tree[x].mn = min(tree[x * 2].mn, tree[x * 2 + 1].mn);
95 tree[x].mx = max(tree[x * 2].mx, tree[x * 2 + 1].mx);
96 }
source code
JuQueen #
10277
Sogang ICPC Team 31
98 ll minimum(int l, int r) {
99 return _minimum(1, 0, c - 1, l, r);
100 }
101
102 ll maximum(int l, int r) {
103 return _maximum(1, 0, c - 1, l, r);
104 }
105
106 void update(int l, int r, ll dv) {
107 _update(1, 0, c - 1, l, r, dv);
108 }
source code
함수 인자가 너무 많으면 헷갈리므로 개인적으로는 첫 호출을 하는 함수를 따로 만들어서
사용하는 중
JuQueen #
10277
Sogang ICPC Team 32
118 string op;
119 cin >> op;
120 if (op[0] == 's') { // ”state”
121 int x;
122 cin >> x;
123 cout << minimum(x, x) << 'n';
124 } else if (op[0] == 'g') { // ”groupchange”
source code
값을 구하는 쿼리는 따로 만들 필요 없이 최솟값이나 최댓값 쿼리로 해결 가능하다
JuQueen #
10277
Sogang ICPC Team 33
124 } else if (op[0] == 'g') { // ”groupchange”
125 int a, b, s;
126 cin >> a >> b >> s;
127
128 ll mn = minimum(a, b), mx = maximum(a, b);
129 if (s > 0 && s + mx > n) {
130 update(a, b, n - mx);
131 cout << n - mx << 'n';
132 } else if (s < 0 && s + mn < 0) {
133 update(a, b, -mn);
134 cout << -mn << 'n';
135 } else {
136 update(a, b, s);
137 cout << s << 'n';
138 }
139 } else { // ”change”
source code
구간 최대/최소를 구해서 증감할 수 있는 만큼 증감해 주고 결과를 출력한다
JuQueen #
10277
Sogang ICPC Team 34
139 } else { // ”change”
140 int x, s;
141 cin >> x >> s;
142
143 ll val = minimum(x, x);
144 if (s > 0 && s + val > n) {
145 update(x, x, n - val);
146 cout << n - val << 'n';
147 } else if (s < 0 && s + val < 0) {
148 update(x, x, -val);
149 cout << -val << 'n';
150 } else {
151 update(x, x, s);
152 cout << s << 'n';
153 }
154 }
155 }
source code
마찬가지.
Lazy Propagation Not on Segment Trees
Sogang ICPC Team 35
Lazy propagation의 아이디어는 세그먼트 트리에 한정해서 쓰이지 않는다
Pixel Triangles #
16572
Sogang ICPC Team 36
2, 000 × 2, 000 크기의 격자 판이 주어지며, 각 픽셀(칸)은 행과 열을 이용해서 위치가
표시된다. 가장 왼쪽 열이 1열, 가장 위쪽 행이 1행이다.
이 때 픽셀 삼각형의 정의는 다음과 같다.
✓ 픽셀 삼각형은 3개의 자연수 A, B, C 에 대해서 P (A, B, C)로 표현된다.
✓ P (A, B, C) = {(x, y) | A ≤ x, B ≤ y, 0 ≤ (x − A) + (y − B) ≤ C − 1}
격자 위의 픽셀들로 구성된 픽셀 삼각형이 n ≤ 4, 000, 000개 주어졌을 때, 픽셀 삼각형들이
덮는 픽셀의 개수를 출력해라.
Pixel Triangles #
16572
Sogang ICPC Team 37
P (1, 2, 3) = {(x, y) | 1 ≤ x, 2 ≤ y, 0 ≤ (x − 1) + (y − 2) ≤ 3 − 1}
Pixel Triangles #
16572
Sogang ICPC Team 38
P (3, 1, 2) = {(x, y) | 3 ≤ x, 1 ≤ y, 0 ≤ (x − 3) + (y − 1) ≤ 2 − 1}
Pixel Triangles #
16572
Sogang ICPC Team 39
P (5, 5, 1) = {(x, y) | 5 ≤ x, 5 ≤ y, 0 ≤ (x − 5) + (y − 5) ≤ 1 − 1}
Pixel Triangles #
16572
Sogang ICPC Team 40
이 때 최종적으로 덮어지는 픽셀의 개수는 9개가 된다
Pixel Triangles #
16572
Sogang ICPC Team 41
최악의 경우?
✓ P (0, 0, 2000)이 4, 000, 000개 있음
✓ bool 배열에 나이브하게 채워넣는다면 배열 액세스 횟수
4, 000, 000 ×
2, 000 (2, 000 + 1)
2
Lazy propagation의 아이디어를 어떻게 적용할 수 있을까?
Pixel Triangles #
16572
Sogang ICPC Team 42
삼각형의 왼쪽 위 꼭짓점에 삼각형의 크기를 미리 적어두자
0 3 0 0 0
0 0 0 0 0
2 0 0 0 0
0 0 0 0 0
0 0 0 0 1
Pixel Triangles #
16572
Sogang ICPC Team 43
모든 픽셀을 왼쪽 오른쪽, 위 아래 순서대로 보면서, 지금 확인하고 있는 칸 ≥ 2라면 오른쪽
칸과 아랫쪽 칸을 갱신
0 3 2 0 0
0 2 0 0 0
2 0 0 0 0
0 0 0 0 0
0 0 0 0 1
Pixel Triangles #
16572
Sogang ICPC Team 44
삼각형 정보들만 적어두고 맨 마지막에만 전부 펼친(?)다
0 3 2 1 0
0 2 1 0 0
2 0 0 0 0
0 0 0 0 0
0 0 0 0 1
Pixel Triangles #
16572
Sogang ICPC Team 45
삼각형 정보들만 적어두고 맨 마지막에만 전부 펼친(?)다
0 3 2 1 0
0 2 1 0 0
2 1 0 0 0
0 0 0 0 0
0 0 0 0 1
Pixel Triangles #
16572
Sogang ICPC Team 46
삼각형 정보들만 적어두고 맨 마지막에만 전부 펼친(?)다
0 3 2 1 0
0 2 1 0 0
2 1 0 0 0
1 0 0 0 0
0 0 0 0 1
Pixel Triangles #
16572
Sogang ICPC Team 47
작업이 끝나면 1 이상이 적힌 칸의 수는 9개!
0 3 2 1 0
0 2 1 0 0
2 1 0 0 0
1 0 0 0 0
0 0 0 0 1
소스는 생략
1회차 연습문제
Sogang ICPC Team 48
✓ 구간 합 구하기 2 #
10999
✓ JuQueen #
10277
✓ Pixel Triangles #
16572
1. 스위치 #
1395
2. XOR #
12844
3. 하늘에서 떨어지는 1, 2, · · · , R − L + 1개의 별 #
17353
4. 수열과 쿼리 13 #
13925
5. Range GCD #
12858

More Related Content

What's hot

CNNの誤差逆伝播/Deconvolutionの計算過程
CNNの誤差逆伝播/Deconvolutionの計算過程CNNの誤差逆伝播/Deconvolutionの計算過程
CNNの誤差逆伝播/Deconvolutionの計算過程
ssuser87f46e
 
20190721 gaussian process
20190721 gaussian process20190721 gaussian process
20190721 gaussian process
Yoichi Tokita
 
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
kiki utagawa
 
Union find(素集合データ構造)
Union find(素集合データ構造)Union find(素集合データ構造)
Union find(素集合データ構造)
AtCoder Inc.
 
レコメンド研究のあれこれ
レコメンド研究のあれこれレコメンド研究のあれこれ
レコメンド研究のあれこれ
Masahiro Sato
 
木を綺麗に描画するアルゴリズム
木を綺麗に描画するアルゴリズム木を綺麗に描画するアルゴリズム
木を綺麗に描画するアルゴリズムmfumi
 
素数の分解法則(フロベニウスやばい) #math_cafe
素数の分解法則(フロベニウスやばい) #math_cafe 素数の分解法則(フロベニウスやばい) #math_cafe
素数の分解法則(フロベニウスやばい) #math_cafe
Junpei Tsuji
 
Gocon2017:Goのロギング周りの考察
Gocon2017:Goのロギング周りの考察Gocon2017:Goのロギング周りの考察
Gocon2017:Goのロギング周りの考察
貴仁 大和屋
 
規格書で読むC++11のスレッド
規格書で読むC++11のスレッド規格書で読むC++11のスレッド
規格書で読むC++11のスレッド
Kohsuke Yuasa
 
[DL輪読会]Deep Learning 第20章 深層生成モデル
[DL輪読会]Deep Learning 第20章 深層生成モデル[DL輪読会]Deep Learning 第20章 深層生成モデル
[DL輪読会]Deep Learning 第20章 深層生成モデル
Deep Learning JP
 
直交領域探索
直交領域探索直交領域探索
直交領域探索
okuraofvegetable
 
[DL輪読会]Deep Learning 第10章 系列モデリング 回帰結合型ニューラルネットワークと再帰型ネットワーク
[DL輪読会]Deep Learning 第10章 系列モデリング 回帰結合型ニューラルネットワークと再帰型ネットワーク[DL輪読会]Deep Learning 第10章 系列モデリング 回帰結合型ニューラルネットワークと再帰型ネットワーク
[DL輪読会]Deep Learning 第10章 系列モデリング 回帰結合型ニューラルネットワークと再帰型ネットワーク
Deep Learning JP
 
プログラミングコンテストでのデータ構造 2 ~動的木編~
プログラミングコンテストでのデータ構造 2 ~動的木編~プログラミングコンテストでのデータ構造 2 ~動的木編~
プログラミングコンテストでのデータ構造 2 ~動的木編~
Takuya Akiba
 
高位合成でDeep learning
高位合成でDeep learning高位合成でDeep learning
高位合成でDeep learning
Mori Labo.
 
Context2Vec 기반 단어 의미 중의성 해소, Word Sense Disambiguation
Context2Vec 기반 단어 의미 중의성 해소, Word Sense DisambiguationContext2Vec 기반 단어 의미 중의성 해소, Word Sense Disambiguation
Context2Vec 기반 단어 의미 중의성 해소, Word Sense Disambiguation
찬희 이
 
双対性
双対性双対性
双対性
Yoichi Iwata
 
딥러닝 기반의 자연어처리 최근 연구 동향
딥러닝 기반의 자연어처리 최근 연구 동향딥러닝 기반의 자연어처리 최근 연구 동향
딥러닝 기반의 자연어처리 최근 연구 동향
LGCNSairesearch
 
AtCoder Regular Contest 024 解説
AtCoder Regular Contest 024 解説AtCoder Regular Contest 024 解説
AtCoder Regular Contest 024 解説
AtCoder Inc.
 
JOIss2014
JOIss2014JOIss2014
JOIss2014
Shunya Satake
 

What's hot (20)

CNNの誤差逆伝播/Deconvolutionの計算過程
CNNの誤差逆伝播/Deconvolutionの計算過程CNNの誤差逆伝播/Deconvolutionの計算過程
CNNの誤差逆伝播/Deconvolutionの計算過程
 
20190721 gaussian process
20190721 gaussian process20190721 gaussian process
20190721 gaussian process
 
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
 
Union find(素集合データ構造)
Union find(素集合データ構造)Union find(素集合データ構造)
Union find(素集合データ構造)
 
レコメンド研究のあれこれ
レコメンド研究のあれこれレコメンド研究のあれこれ
レコメンド研究のあれこれ
 
木を綺麗に描画するアルゴリズム
木を綺麗に描画するアルゴリズム木を綺麗に描画するアルゴリズム
木を綺麗に描画するアルゴリズム
 
素数の分解法則(フロベニウスやばい) #math_cafe
素数の分解法則(フロベニウスやばい) #math_cafe 素数の分解法則(フロベニウスやばい) #math_cafe
素数の分解法則(フロベニウスやばい) #math_cafe
 
Gocon2017:Goのロギング周りの考察
Gocon2017:Goのロギング周りの考察Gocon2017:Goのロギング周りの考察
Gocon2017:Goのロギング周りの考察
 
規格書で読むC++11のスレッド
規格書で読むC++11のスレッド規格書で読むC++11のスレッド
規格書で読むC++11のスレッド
 
[DL輪読会]Deep Learning 第20章 深層生成モデル
[DL輪読会]Deep Learning 第20章 深層生成モデル[DL輪読会]Deep Learning 第20章 深層生成モデル
[DL輪読会]Deep Learning 第20章 深層生成モデル
 
直交領域探索
直交領域探索直交領域探索
直交領域探索
 
[DL輪読会]Deep Learning 第10章 系列モデリング 回帰結合型ニューラルネットワークと再帰型ネットワーク
[DL輪読会]Deep Learning 第10章 系列モデリング 回帰結合型ニューラルネットワークと再帰型ネットワーク[DL輪読会]Deep Learning 第10章 系列モデリング 回帰結合型ニューラルネットワークと再帰型ネットワーク
[DL輪読会]Deep Learning 第10章 系列モデリング 回帰結合型ニューラルネットワークと再帰型ネットワーク
 
プログラミングコンテストでのデータ構造 2 ~動的木編~
プログラミングコンテストでのデータ構造 2 ~動的木編~プログラミングコンテストでのデータ構造 2 ~動的木編~
プログラミングコンテストでのデータ構造 2 ~動的木編~
 
高位合成でDeep learning
高位合成でDeep learning高位合成でDeep learning
高位合成でDeep learning
 
Context2Vec 기반 단어 의미 중의성 해소, Word Sense Disambiguation
Context2Vec 기반 단어 의미 중의성 해소, Word Sense DisambiguationContext2Vec 기반 단어 의미 중의성 해소, Word Sense Disambiguation
Context2Vec 기반 단어 의미 중의성 해소, Word Sense Disambiguation
 
双対性
双対性双対性
双対性
 
딥러닝 기반의 자연어처리 최근 연구 동향
딥러닝 기반의 자연어처리 최근 연구 동향딥러닝 기반의 자연어처리 최근 연구 동향
딥러닝 기반의 자연어처리 최근 연구 동향
 
Map
MapMap
Map
 
AtCoder Regular Contest 024 解説
AtCoder Regular Contest 024 解説AtCoder Regular Contest 024 解説
AtCoder Regular Contest 024 解説
 
JOIss2014
JOIss2014JOIss2014
JOIss2014
 

Similar to 세그먼트 트리 느리게 업데이트하기 - Sogang ICPC Team, 2020 Winter

Lazy Propagation on Segment Trees - Sogang ICPC Team, 2019
Lazy Propagation on Segment Trees - Sogang ICPC Team, 2019Lazy Propagation on Segment Trees - Sogang ICPC Team, 2019
Lazy Propagation on Segment Trees - Sogang ICPC Team, 2019
Suhyun Park
 
3ds maxscript 튜토리얼_20151206_서진택
3ds maxscript 튜토리얼_20151206_서진택3ds maxscript 튜토리얼_20151206_서진택
3ds maxscript 튜토리얼_20151206_서진택
JinTaek Seo
 
확통 회귀분석
확통 회귀분석확통 회귀분석
확통 회귀분석
jaypi Ko
 
Persistent Segment Tree - Sogang ICPC Team, 2019
Persistent Segment Tree - Sogang ICPC Team, 2019Persistent Segment Tree - Sogang ICPC Team, 2019
Persistent Segment Tree - Sogang ICPC Team, 2019
Suhyun Park
 
하스켈 성능 튜닝
하스켈 성능 튜닝하스켈 성능 튜닝
하스켈 성능 튜닝
민석 이
 
R 스터디 첫번째
R 스터디 첫번째R 스터디 첫번째
R 스터디 첫번째
Jaeseok Park
 
Tensorflow regression 텐서플로우 회귀
Tensorflow regression 텐서플로우 회귀Tensorflow regression 텐서플로우 회귀
Tensorflow regression 텐서플로우 회귀
beom kyun choi
 
RLCode와 A3C 쉽고 깊게 이해하기
RLCode와 A3C 쉽고 깊게 이해하기RLCode와 A3C 쉽고 깊게 이해하기
RLCode와 A3C 쉽고 깊게 이해하기
Woong won Lee
 
2019 ppc answers
2019 ppc answers2019 ppc answers
2019 ppc answers
승혁 조
 
딥러닝기본-신경망기초
딥러닝기본-신경망기초딥러닝기본-신경망기초
딥러닝기본-신경망기초
jaypi Ko
 
Variational AutoEncoder(VAE)
Variational AutoEncoder(VAE)Variational AutoEncoder(VAE)
Variational AutoEncoder(VAE)
강민국 강민국
 
Code로 이해하는 RNN
Code로 이해하는 RNNCode로 이해하는 RNN
Code로 이해하는 RNN
SANG WON PARK
 
Coursera Machine Learning으로 기계학습 배우기 : week2
Coursera Machine Learning으로 기계학습 배우기 : week2Coursera Machine Learning으로 기계학습 배우기 : week2
Coursera Machine Learning으로 기계학습 배우기 : week2
Kwangsik Lee
 
자료구조5보고서
자료구조5보고서자료구조5보고서
자료구조5보고서KimChangHoen
 
해커에게 전해들은 머신러닝 #3
해커에게 전해들은 머신러닝 #3해커에게 전해들은 머신러닝 #3
해커에게 전해들은 머신러닝 #3
Haesun Park
 
Project#5 최단거리 찾기 D0 Hwp
Project#5 최단거리 찾기 D0 HwpProject#5 최단거리 찾기 D0 Hwp
Project#5 최단거리 찾기 D0 HwpKimjeongmoo
 
파이썬 스터디 2주차
파이썬 스터디 2주차파이썬 스터디 2주차
파이썬 스터디 2주차
Han Sung Kim
 
R 프로그래밍-향상된 데이타 조작
R 프로그래밍-향상된 데이타 조작R 프로그래밍-향상된 데이타 조작
R 프로그래밍-향상된 데이타 조작
Terry Cho
 

Similar to 세그먼트 트리 느리게 업데이트하기 - Sogang ICPC Team, 2020 Winter (20)

Lazy Propagation on Segment Trees - Sogang ICPC Team, 2019
Lazy Propagation on Segment Trees - Sogang ICPC Team, 2019Lazy Propagation on Segment Trees - Sogang ICPC Team, 2019
Lazy Propagation on Segment Trees - Sogang ICPC Team, 2019
 
3ds maxscript 튜토리얼_20151206_서진택
3ds maxscript 튜토리얼_20151206_서진택3ds maxscript 튜토리얼_20151206_서진택
3ds maxscript 튜토리얼_20151206_서진택
 
확통 회귀분석
확통 회귀분석확통 회귀분석
확통 회귀분석
 
Persistent Segment Tree - Sogang ICPC Team, 2019
Persistent Segment Tree - Sogang ICPC Team, 2019Persistent Segment Tree - Sogang ICPC Team, 2019
Persistent Segment Tree - Sogang ICPC Team, 2019
 
하스켈 성능 튜닝
하스켈 성능 튜닝하스켈 성능 튜닝
하스켈 성능 튜닝
 
R 스터디 첫번째
R 스터디 첫번째R 스터디 첫번째
R 스터디 첫번째
 
Tensorflow regression 텐서플로우 회귀
Tensorflow regression 텐서플로우 회귀Tensorflow regression 텐서플로우 회귀
Tensorflow regression 텐서플로우 회귀
 
RLCode와 A3C 쉽고 깊게 이해하기
RLCode와 A3C 쉽고 깊게 이해하기RLCode와 A3C 쉽고 깊게 이해하기
RLCode와 A3C 쉽고 깊게 이해하기
 
2019 ppc answers
2019 ppc answers2019 ppc answers
2019 ppc answers
 
Rdatamining
Rdatamining Rdatamining
Rdatamining
 
딥러닝기본-신경망기초
딥러닝기본-신경망기초딥러닝기본-신경망기초
딥러닝기본-신경망기초
 
Variational AutoEncoder(VAE)
Variational AutoEncoder(VAE)Variational AutoEncoder(VAE)
Variational AutoEncoder(VAE)
 
Code로 이해하는 RNN
Code로 이해하는 RNNCode로 이해하는 RNN
Code로 이해하는 RNN
 
Coursera Machine Learning으로 기계학습 배우기 : week2
Coursera Machine Learning으로 기계학습 배우기 : week2Coursera Machine Learning으로 기계학습 배우기 : week2
Coursera Machine Learning으로 기계학습 배우기 : week2
 
자료구조5보고서
자료구조5보고서자료구조5보고서
자료구조5보고서
 
R_datamining
R_dataminingR_datamining
R_datamining
 
해커에게 전해들은 머신러닝 #3
해커에게 전해들은 머신러닝 #3해커에게 전해들은 머신러닝 #3
해커에게 전해들은 머신러닝 #3
 
Project#5 최단거리 찾기 D0 Hwp
Project#5 최단거리 찾기 D0 HwpProject#5 최단거리 찾기 D0 Hwp
Project#5 최단거리 찾기 D0 Hwp
 
파이썬 스터디 2주차
파이썬 스터디 2주차파이썬 스터디 2주차
파이썬 스터디 2주차
 
R 프로그래밍-향상된 데이타 조작
R 프로그래밍-향상된 데이타 조작R 프로그래밍-향상된 데이타 조작
R 프로그래밍-향상된 데이타 조작
 

세그먼트 트리 느리게 업데이트하기 - Sogang ICPC Team, 2020 Winter

  • 1. #1— 세그먼트트리느리게업데이트하기 Lazy Propagation on Segment Trees by Suhyun Park Sogang ICPC Team – 2020 겨울 고급 스터디 acm.sogang.ac.kr
  • 2. 환영합니다! Sogang ICPC Team 1 “고급” 스터디에 오신 여러분을 환영합니다!
  • 3. 환영합니다! Sogang ICPC Team 2 저는... ✓ 박수현 – @shiftpsh / shiftpsh.com ✓ Sogang ICPC Team 전임 학회장 – 2019년 ✓ ICPC 2019 Seoul Regional에 팀 Redshift로 참가 – 8위 ✓ solved.ac를 만든 사람!
  • 4. “고급” 스터디를 시작하기 전에... Sogang ICPC Team 3 “고급” 스터디는 초급이나 중급 스터디와는 진행방식이 좀 다릅니다 ✓ 옆 동네에서 하는 팀 빌딩이나 모의고사 등 재밌는 것들 → 없어요 ✓ 기본적으로 혼자 열심히 하셔야 해요 – 여기 오실 정도의 여러분들이 PS에 미친 분들이라는 건 확실해 보이니 걱정하지 않겠습니다
  • 5. “고급” 스터디를 시작하기 전에... Sogang ICPC Team 4 다루게 되는 것들 ✓ solved.ac 기준으로 에서 사이의 문제들 ✓ 실무에서는 전혀 쓸 것 같지 않고 실제로도 별로 안 쓰이는 생소한 알고리즘과 자료구조들 – 하지만 대회에서는 나온다 ✓ 여하튼 ICPC 등의 “대회 준비”에 초점이 맞춰져 있습니다
  • 6. “고급” 스터디를 시작하기 전에... Sogang ICPC Team 5 “고급”에 붙어 있는 따옴표는 뭐에요? ✓ 고급 스터디에서 다루는 자료구조와 알고리즘들은 대회 준비의 필요조건이지 충분조건이 아닙니다 – 이런 거 많이 아는 것보다 이미 아는 알고리즘을 잘 써먹는 방법을 공부하는 게 대회 성적에 훨씬 도움이 됩니다 ✓ 진짜 “고급” – 이미 알고 있는 알고리즘들을 잘 써먹는 능력을 기르는 스터디 – 팀 연습 등
  • 7. “고급” 스터디를 시작하기 전에... Sogang ICPC Team 6 그럼 이거 왜 하는 거에요? ✓ 모르면 아예 못 푸는 내용들을 대비하기 위해 ✓ 남들한테는 다 웰노운인데 나한테만 아닌 것들을 나에게도 웰노운으로 만들어 써먹기 위해 – 팀노트에 적어가세요 ✓ solved.ac 경험치 올리기 위해
  • 8. Remarks on Segment Trees Sogang ICPC Team 7 1–10 1–5 6–10 1–3 4–5 6–8 9–10 1–2 3 4 5 6–7 8 9 10 1 2 6 7 f (x, s, e, · · · ) = f ( 2x, s, ⌊ s + e 2 ⌋ , · · · ) + f ( 2x + 1, ⌊ s + e 2 ⌋ + 1, e, · · · )
  • 9. Remarks on Segment Trees Sogang ICPC Team 8 1–10 1–5 6–10 1–3 4–5 6–8 9–10 1–2 3 4 5 6–7 8 9 10 1 2 6 7 A5 · · · A9 의 합?
  • 10. Remarks on Segment Trees Sogang ICPC Team 9 ✓ Al · · · Ar 의 합 쿼리 = O (log n) ✓ Ai 업데이트 = O (log n)
  • 11. Lazy Propagation Sogang ICPC Team 10 ✓ Al · · · Ar 의 합 쿼리 ✓ Al · · · Ar 업데이트 의 두 쿼리를 처리해야 한다고 생각해 보자 – 하나하나 업데이트한다면 쿼리 한 번에 O ((r − l) log n) → 사실상 O (n log n)
  • 12. Lazy Propagation Sogang ICPC Team 11 쿼리 한 번에 O (n log n)은 느려도 너무 느리다 → 업데이트할 때 매번 리프 노드까지 보내지 말자 → 트리를 하나 더 만들어서 거기다 업데이트하고 쿼리할 때 한꺼번에 업데이트하자
  • 13. Lazy Propagation Sogang ICPC Team 12 40 ll a[1000001], tree[1048576 * 2], lazy[1048576 * 2]; 41 42 void _propagate(int x, int s, int e) { 43 if (!lazy[x]) return; 44 tree[x] += (e - s + 1) * lazy[x]; 45 if (s != e) { 46 lazy[x * 2] += lazy[x]; 47 lazy[x * 2 + 1] += lazy[x]; 48 } 49 lazy[x] = 0; 50 } lazy라는 이름으로 별도의 트리를 만든다
  • 14. Lazy Propagation Sogang ICPC Team 13 40 ll a[1000001], tree[1048576 * 2], lazy[1048576 * 2]; 41 42 void _propagate(int x, int s, int e) { 43 if (!lazy[x]) return; 44 tree[x] += (e - s + 1) * lazy[x]; 45 if (s != e) { 46 lazy[x * 2] += lazy[x]; 47 lazy[x * 2 + 1] += lazy[x]; 48 } 49 lazy[x] = 0; 50 } 노드 x에 아직 업데이트하지 않은 값이 있다면 트리에 업데이트해주는 메서드
  • 15. Lazy Propagation Sogang ICPC Team 14 52 ll _sum(int x, int s, int e, int l, int r) { 53 _propagate(x, s, e); 54 if (l > e || r < s) return 0; 55 if (l <= s && e <= r) return tree[x]; 56 int m = (s + e) / 2; 57 return _sum(x * 2 , s, m, l, r) + 58 _sum(x * 2 + 1, m + 1, e, l, r); 59 } 합 쿼리를 계산할 때 propagation을 해 줘야 한다
  • 16. Lazy Propagation Sogang ICPC Team 15 61 void _update(int x, int s, int e, int l, int r, ll dv) { 62 _propagate(x, s, e); 63 if (l > e || r < s) return; 64 if (l <= s && e <= r) { 65 tree[x] += (e - s + 1) * dv; 66 if (s != e) { 67 lazy[x * 2] += dv; 68 lazy[x * 2 + 1] += dv; 69 } 70 return; 71 } 72 int m = (s + e) / 2; 73 _update(x * 2 , s, m, l, r, dv); 74 _update(x * 2 + 1, m + 1, e, l, r, dv); 75 tree[x] = tree[x * 2] + tree[x * 2 + 1]; 76 } 업데이트할 때도 propagation을 해 줘야 한다
  • 17. Lazy Propagation Sogang ICPC Team 16 61 void _update(int x, int s, int e, int l, int r, ll dv) { 62 _propagate(x, s, e); 63 if (l > e || r < s) return; 64 if (l <= s && e <= r) { 65 tree[x] += (e - s + 1) * dv; 66 if (s != e) { 67 lazy[x * 2] += dv; 68 lazy[x * 2 + 1] += dv; 69 } 70 return; 71 } 72 int m = (s + e) / 2; 73 _update(x * 2 , s, m, l, r, dv); 74 _update(x * 2 + 1, m + 1, e, l, r, dv); 75 tree[x] = tree[x * 2] + tree[x * 2 + 1]; 76 } 현재 확인하는 구간이 업데이트 구간 안에 있다면 리프 노드까지 가지 않고 lazy를 업데이트하고 끝낸다
  • 18. Lazy Propagation Sogang ICPC Team 17 89 ll sum(int l, int r) { 90 return _sum(1, 1, 1000000, l, r); 91 } 92 93 void update(int l, int r, ll dv) { 94 _update(1, 1, 1000000, l, r, dv); 95 } 96 97 void initialize() { 98 _initialize(1, 1, 1000000); 99 } _initialize는 세그먼트 트리의 그것과 같으므로 생략
  • 19. 구간 합 구하기 2 # 10999 Sogang ICPC Team 18 ✓ n ≤ 106 ✓ m + k ≤ 20000 구현해보자
  • 20. 구간 합 구하기 2 # 10999 Sogang ICPC Team 19 115 while (q--) { 116 int op, l, r; 117 cin >> op >> l >> r; 118 if (op == 1) { 119 ll dv; 120 cin >> dv; 121 update(l, r, dv); 122 } else { // op == 2 123 cout << sum(l, r) << 'n'; 124 } 125 } source code
  • 21. JuQueen # 10277 Sogang ICPC Team 20 코어가 4, 587, 520개인 컴퓨터의 클럭을 변경하는 프로그램을 짜야 한다. N 단계의 클럭이 가능하고 ✓ CPU x의 클럭을 s단계만큼 증감 ✓ CPU a · · · b의 클럭을 s단계만큼 증감 ✓ CPU x의 클럭 단계 출력 중 하나를 할 수 있다. 클럭은 한 단계씩만 올라가거나 내려가며, 여러 코어에 대해 여러 단계를 한꺼번에 증감할 경우 그 중 하나라도 0단계나 N 단계에 도달하면 증감을 종료하고 증감한 만큼의 단계를 출력한다.
  • 22. JuQueen # 10277 Sogang ICPC Team 21 클럭은 한 단계씩만 올라가거나 내려가며, 여러 코어에 대해 여러 단계를 한꺼번에 증감할 경우 그 중 하나라도 0단계나 N 단계에 도달하면 증감을 종료하고 증감한 만큼의 단계를 출력한다. ✓ 지금 클럭들이 1, 2, 3, 4고 N = 6이라면, 클럭 4단계를 올리라는 명령을 내린다면 2 단계만 올라가고 끝난다
  • 23. JuQueen # 10277 Sogang ICPC Team 22 CPU a · · · b의 클럭 단계의 최솟값을 mn, 최댓값을 mx라 하고, s만큼 증감하고자 한다면 ✓ mx + s > N 이라면? N − mx만큼만 올릴 수 있다 ✓ mn + s < 0이라면? mn만큼만 내릴 수 있다 ✓ 둘 다 아니라면 s만큼 올릴 수 있다
  • 24. JuQueen # 10277 Sogang ICPC Team 23 세 가지 연산을 할 수 있는 자료구조가 필요 ✓ 인덱스 l · · · r에서의 최솟값 구하기 ✓ 인덱스 l · · · r에서의 최댓값 구하기 ✓ 인덱스 l · · · r을 전부 s만큼 증가시키기 하나의 원소 i에 대해서만 연산할 경우 l = r = i
  • 25. JuQueen # 10277 Sogang ICPC Team 24 A = {a0, a1, · · · , an} A′ = {a0 + d, a1 + d, · · · , an + d} 이라고 하면 max a′∈A′ ( a′ ) = max a∈A (a) + d min a′∈A′ ( a′ ) = min a∈A (a) + d 이 성립 → 그냥 더해주면 된다. 별 문제 없다
  • 26. JuQueen # 10277 Sogang ICPC Team 25 ✓ 인덱스 l · · · r에서의 최솟값 구하기 ✓ 인덱스 l · · · r에서의 최댓값 구하기 · · · 를 하기 위해 세그먼트 트리를 튜플 ⟨min, max⟩ 로 만들고 ✓ 인덱스 l · · · r을 전부 s만큼 증가시키기 · · · 를 하기 위해 lazy propagate 하면 되겠다!
  • 27. JuQueen # 10277 Sogang ICPC Team 26 40 struct mii { 41 ll mn, mx; 42 }; 43 44 mii tree[8388608 * 2]; 45 int lazy[8388608 * 2]; 46 47 int inf = 987654321; 48 int c, n, o; source code first, second는 헷갈리니까 struct를 새로 만든다. 어차피 정렬할 것도 아닌데· · ·
  • 28. JuQueen # 10277 Sogang ICPC Team 27 50 void _propagate(int x, int s, int e) { 51 if (!lazy[x]) return; 52 tree[x].mn += lazy[x]; 53 tree[x].mx += lazy[x]; 54 if (s != e) { 55 lazy[x * 2] += lazy[x]; 56 lazy[x * 2 + 1] += lazy[x]; 57 } 58 lazy[x] = 0; 59 } source code Propagation – 더해주는 쿼리를 처리해 주기 위함
  • 29. JuQueen # 10277 Sogang ICPC Team 28 61 ll _minimum(int x, int s, int e, int l, int r) { 62 _propagate(x, s, e); 63 if (l > e || r < s) return inf; 64 if (l <= s && e <= r) return tree[x].mn; 65 int m = (s + e) / 2; 66 return min(_minimum(x * 2, s, m, l, r), 67 _minimum(x * 2 + 1, m + 1, e, l, r)); 68 } source code 구간 최솟값 쿼리를 처리하면서 propagation도 같이 한다
  • 30. JuQueen # 10277 Sogang ICPC Team 29 70 ll _maximum(int x, int s, int e, int l, int r) { 71 _propagate(x, s, e); 72 if (l > e || r < s) return 0; 73 if (l <= s && e <= r) return tree[x].mx; 74 int m = (s + e) / 2; 75 return max(_maximum(x * 2, s, m, l, r), 76 _maximum(x * 2 + 1, m + 1, e, l, r)); 77 } source code 최댓값에 대해서도 동일하게 처리해 준다
  • 31. JuQueen # 10277 Sogang ICPC Team 30 79 void _update(int x, int s, int e, int l, int r, ll dv) { 80 _propagate(x, s, e); 81 if (l > e || r < s) return; 82 if (l <= s && e <= r) { 83 tree[x].mn += dv; 84 tree[x].mx += dv; 85 if (s != e) { 86 lazy[x * 2] += dv; 87 lazy[x * 2 + 1] += dv; 88 } 89 return; 90 } 91 int m = (s + e) / 2; 92 _update(x * 2 , s, m, l, r, dv); 93 _update(x * 2 + 1, m + 1, e, l, r, dv); 94 tree[x].mn = min(tree[x * 2].mn, tree[x * 2 + 1].mn); 95 tree[x].mx = max(tree[x * 2].mx, tree[x * 2 + 1].mx); 96 } source code
  • 32. JuQueen # 10277 Sogang ICPC Team 31 98 ll minimum(int l, int r) { 99 return _minimum(1, 0, c - 1, l, r); 100 } 101 102 ll maximum(int l, int r) { 103 return _maximum(1, 0, c - 1, l, r); 104 } 105 106 void update(int l, int r, ll dv) { 107 _update(1, 0, c - 1, l, r, dv); 108 } source code 함수 인자가 너무 많으면 헷갈리므로 개인적으로는 첫 호출을 하는 함수를 따로 만들어서 사용하는 중
  • 33. JuQueen # 10277 Sogang ICPC Team 32 118 string op; 119 cin >> op; 120 if (op[0] == 's') { // ”state” 121 int x; 122 cin >> x; 123 cout << minimum(x, x) << 'n'; 124 } else if (op[0] == 'g') { // ”groupchange” source code 값을 구하는 쿼리는 따로 만들 필요 없이 최솟값이나 최댓값 쿼리로 해결 가능하다
  • 34. JuQueen # 10277 Sogang ICPC Team 33 124 } else if (op[0] == 'g') { // ”groupchange” 125 int a, b, s; 126 cin >> a >> b >> s; 127 128 ll mn = minimum(a, b), mx = maximum(a, b); 129 if (s > 0 && s + mx > n) { 130 update(a, b, n - mx); 131 cout << n - mx << 'n'; 132 } else if (s < 0 && s + mn < 0) { 133 update(a, b, -mn); 134 cout << -mn << 'n'; 135 } else { 136 update(a, b, s); 137 cout << s << 'n'; 138 } 139 } else { // ”change” source code 구간 최대/최소를 구해서 증감할 수 있는 만큼 증감해 주고 결과를 출력한다
  • 35. JuQueen # 10277 Sogang ICPC Team 34 139 } else { // ”change” 140 int x, s; 141 cin >> x >> s; 142 143 ll val = minimum(x, x); 144 if (s > 0 && s + val > n) { 145 update(x, x, n - val); 146 cout << n - val << 'n'; 147 } else if (s < 0 && s + val < 0) { 148 update(x, x, -val); 149 cout << -val << 'n'; 150 } else { 151 update(x, x, s); 152 cout << s << 'n'; 153 } 154 } 155 } source code 마찬가지.
  • 36. Lazy Propagation Not on Segment Trees Sogang ICPC Team 35 Lazy propagation의 아이디어는 세그먼트 트리에 한정해서 쓰이지 않는다
  • 37. Pixel Triangles # 16572 Sogang ICPC Team 36 2, 000 × 2, 000 크기의 격자 판이 주어지며, 각 픽셀(칸)은 행과 열을 이용해서 위치가 표시된다. 가장 왼쪽 열이 1열, 가장 위쪽 행이 1행이다. 이 때 픽셀 삼각형의 정의는 다음과 같다. ✓ 픽셀 삼각형은 3개의 자연수 A, B, C 에 대해서 P (A, B, C)로 표현된다. ✓ P (A, B, C) = {(x, y) | A ≤ x, B ≤ y, 0 ≤ (x − A) + (y − B) ≤ C − 1} 격자 위의 픽셀들로 구성된 픽셀 삼각형이 n ≤ 4, 000, 000개 주어졌을 때, 픽셀 삼각형들이 덮는 픽셀의 개수를 출력해라.
  • 38. Pixel Triangles # 16572 Sogang ICPC Team 37 P (1, 2, 3) = {(x, y) | 1 ≤ x, 2 ≤ y, 0 ≤ (x − 1) + (y − 2) ≤ 3 − 1}
  • 39. Pixel Triangles # 16572 Sogang ICPC Team 38 P (3, 1, 2) = {(x, y) | 3 ≤ x, 1 ≤ y, 0 ≤ (x − 3) + (y − 1) ≤ 2 − 1}
  • 40. Pixel Triangles # 16572 Sogang ICPC Team 39 P (5, 5, 1) = {(x, y) | 5 ≤ x, 5 ≤ y, 0 ≤ (x − 5) + (y − 5) ≤ 1 − 1}
  • 41. Pixel Triangles # 16572 Sogang ICPC Team 40 이 때 최종적으로 덮어지는 픽셀의 개수는 9개가 된다
  • 42. Pixel Triangles # 16572 Sogang ICPC Team 41 최악의 경우? ✓ P (0, 0, 2000)이 4, 000, 000개 있음 ✓ bool 배열에 나이브하게 채워넣는다면 배열 액세스 횟수 4, 000, 000 × 2, 000 (2, 000 + 1) 2 Lazy propagation의 아이디어를 어떻게 적용할 수 있을까?
  • 43. Pixel Triangles # 16572 Sogang ICPC Team 42 삼각형의 왼쪽 위 꼭짓점에 삼각형의 크기를 미리 적어두자 0 3 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 1
  • 44. Pixel Triangles # 16572 Sogang ICPC Team 43 모든 픽셀을 왼쪽 오른쪽, 위 아래 순서대로 보면서, 지금 확인하고 있는 칸 ≥ 2라면 오른쪽 칸과 아랫쪽 칸을 갱신 0 3 2 0 0 0 2 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 1
  • 45. Pixel Triangles # 16572 Sogang ICPC Team 44 삼각형 정보들만 적어두고 맨 마지막에만 전부 펼친(?)다 0 3 2 1 0 0 2 1 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 1
  • 46. Pixel Triangles # 16572 Sogang ICPC Team 45 삼각형 정보들만 적어두고 맨 마지막에만 전부 펼친(?)다 0 3 2 1 0 0 2 1 0 0 2 1 0 0 0 0 0 0 0 0 0 0 0 0 1
  • 47. Pixel Triangles # 16572 Sogang ICPC Team 46 삼각형 정보들만 적어두고 맨 마지막에만 전부 펼친(?)다 0 3 2 1 0 0 2 1 0 0 2 1 0 0 0 1 0 0 0 0 0 0 0 0 1
  • 48. Pixel Triangles # 16572 Sogang ICPC Team 47 작업이 끝나면 1 이상이 적힌 칸의 수는 9개! 0 3 2 1 0 0 2 1 0 0 2 1 0 0 0 1 0 0 0 0 0 0 0 0 1 소스는 생략
  • 49. 1회차 연습문제 Sogang ICPC Team 48 ✓ 구간 합 구하기 2 # 10999 ✓ JuQueen # 10277 ✓ Pixel Triangles # 16572 1. 스위치 # 1395 2. XOR # 12844 3. 하늘에서 떨어지는 1, 2, · · · , R − L + 1개의 별 # 17353 4. 수열과 쿼리 13 # 13925 5. Range GCD # 12858