https://www.acmicpc.net/problem/17474
17474번: 수열과 쿼리 26
길이가 N인 수열 A1, A2, ..., AN이 주어진다. 이때, 다음 쿼리를 수행하는 프로그램을 작성하시오. 1 L R X: 모든 L ≤ i ≤ R에 대해서 Ai = min(Ai, X) 를 적용한다. 2 L R: max(AL, AL+1, ..., AR)을 출력한다. 3
www.acmicpc.net
[알고리즘 분류]
Segment tree beats
greedev에게 세그비츠가 웰논인지 물어봤는데, 다음과 같은 답변을 받았다.

(수쿼 25~30은 모두 세그비츠를 사용한다고 한다.)
나는 정말 무식하지만, 최대한 열심히 설명해보도록 하겠다. 나보다 설명을 몇십배는 잘 해둔 글이 수두룩하기 때문에, 나의 글로 이해하기가 힘들다면 매우 높은 확률로 내가 글을 못 써서 그런 것이다
공부하고 싶다면 삼성 소프트웨어 멤버십 글을 참고하였으면 좋겠다.
Segment Tree Beats는, lazy조건을 약화하고, 리턴조건을 강화하는 기술이다. 정말정말 어렵다. 레이지 세그 최종진화
문제의 업데이트 쿼리를 보자.
어떤 구간
우리는 구간의 합을 구해야 하므로, '구간 내 수들이 모두 같을 때' 값에 변화를 주도록 하면 쉽게 구간 합을 구할 수 있다.
그러나 [100000, 1, 100000, 1, 100000, ... , 1]과 같은 구간에서
두 번째로 큰 수를 활용하는 방법을 생각해야 할 것 같다. 구간에서 가장 큰 값을 max, 두 번째로 큰 값을 max2라고 하자.

위와 같은 상황에서,

서로 다른 두 수가 하나로 합쳐졌다. 이런 이유로
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
|
#include <iostream>
#include <algorithm>
using namespace std;
#define endl '\n'
typedef long long ll;
struct Node{
ll max, cnt, max2, sum;
};
int N, M;
int a[1010101];
Node seg[4040404];
Node merge(Node l, Node r){
if (l.max == r.max) return {l.max, l.cnt + r.cnt, max(l.max2, r.max2), l.sum + r.sum};
if (l.max < r.max) return {r.max, r.cnt, max(l.max, r.max2), l.sum + r.sum};
return {l.max, l.cnt, max(l.max2, r.max), l.sum + r.sum};
}
Node init(int x, int s, int e){
if (s == e) return seg[x] = {a[s], 1, -1, a[s]};
int m = (s + e) / 2;
return seg[x] = merge(init(x * 2, s, m), init(x * 2 + 1, m + 1, e));
}
void lazyProp(int x, int s, int e){
if (s == e) return;
for (int i = x * 2; i <= x * 2 + 1; i++){
if (seg[x].max < seg[i].max){
seg[i].sum -= seg[x].max * seg[i].cnt;
seg[i].max = seg[x].max;
}
}
}
void update(int x, int s, int e, int l, int r, int k){
lazyProp(x, s, e);
if (r < s || e < l || seg[x].max <= k) return;
if (l <= s && e <= r && seg[x].max2 < k){
seg[x].sum -= seg[x].max * seg[x].cnt;
seg[x].max = k;
lazyProp(x, s, e);
return;
}
int m = (s + e) / 2;
update(x * 2, s, m, l, r, k);
update(x * 2 + 1, m + 1, e, l, r, k);
seg[x] = merge(seg[x * 2], seg[x * 2 + 1]);
}
ll getMax(int x, int s, int e, int l, int r){
lazyProp(x, s, e);
if (r < s || e < l) return 0;
if (l <= s && e <= r) return seg[x].max;
int m = (s + e) / 2;
return max(getMax(x * 2, s, m, l, r), getMax(x * 2 + 1, m + 1, e, l, r));
}
ll getSum(int x, int s, int e, int l, int r){
lazyProp(x, s, e);
if (r < s || e < l) return 0;
if (l <= s && e <= r) return seg[x].sum;
int m = (s + e) / 2;
return getSum(x * 2, s, m, l, r) + getSum(x * 2 + 1, m + 1, e, l, r);
}
int main(){
ios_base::sync_with_stdio(false); cin.tie(0);
cin >> N;
for (int i = 1; i <= N; i++){
cin >> a[i];
}
init(1, 1, N);
cin >> M;
for (int qr = 0; qr < M; qr++){
int Q, i, j, k;
cin >> Q >> i >> j;
if (Q == 1){
cin >> k;
update(1, 1, N, i, j, k);
}
else if (Q == 2){
cout << getMax(1, 1, N, i, j) << endl;
}
else{
cout << getSum(1, 1, N, i, j) << endl;
}
}
return 0;
}
|
cs |

너무 어려운 주제라서 설명을 너무 못했다. 오류도 엄청 많을 것 같다..
'알고리즘' 카테고리의 다른 글
Adding Points in a Half Convex Hull (5) | 2022.11.05 |
---|---|
기하 알고리즘 - Convex Hull, Rotating Calipers (0) | 2022.10.24 |
기하 알고리즘 - 기초 (0) | 2022.10.20 |
Offline Dynamic Connectivity - 오프라인 동적 연결성 판정 (0) | 2022.06.12 |