15561번: 구간 합 최대? 2
첫 번째 줄에 정수 N과 Q, U, V가 입력된다. (1 ≤ N, Q ≤ 105, - 5 ≤ U, V ≤ 5) 두 번째 줄에 정수 K1, K2, ..., KN이 주어진다. (-102 ≤ Ki ≤ 102) 세 번째 줄부터 쿼리가
www.acmicpc.net
목차
- 사전 지식
- 문제 풀이
사전 지식
문제 풀이
U×(Ki+Ki+1+⋯+Kj)+V×(j−i) 의미
이 식은 (UKi+UKi+1+⋯+UKj)+∑j−1k=iV(UKi+UKi+1+⋯+UKj)+∑j−1k=iV 로 나타낼 수 있으며
조금 더 변환하면 (UKi+V)+(UKi+1+V)+⋯+(UKj+V)−V(UKi+V)+(UKi+1+V)+⋯+(UKj+V)−V 로 나타낼 수 있다.
즉, 각 원소를 KiKi가 아닌 UKi+VUKi+V로 바꾼 배열을 arr
이라고 하면 문제의 쿼리를 다음과 같이 재해석할 수 있다.
구간 [A,B][A,B]에 대해, arr
에서 가장 큰 연속합을 구한다.
어떤 배열에 대해 가장 큰 연속합을 구하는 테크닉은 여기를 참조하기 바란다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// BOJ 15561 | |
// Struct SegTree | |
#include <bits/stdc++.h> | |
using namespace std; | |
using ll = long long; | |
ll INF = 1e12; | |
struct node { | |
ll lmax, rmax, max, sum; | |
}; | |
ll sz; | |
vector<node> tree; | |
node merge(node &l, node &r) { | |
node ret; | |
ret.lmax = max(l.lmax, l.sum+r.lmax); | |
ret.rmax = max(r.rmax, r.sum+l.rmax); | |
ret.max = max({l.max, r.max, l.rmax+r.lmax}); | |
ret.sum = l.sum + r.sum; | |
return ret; | |
} | |
void update(ll idx, ll x) { | |
idx += sz; | |
tree[idx] = {x, x, x, x}; | |
while (idx /= 2) tree[idx] = merge(tree[2*idx], tree[2*idx+1]); | |
} | |
ll query(ll a, ll b) { | |
a += sz; b += sz; | |
if (a == b) return tree[a].max; | |
node left = tree[a]; | |
node right = tree[b]; | |
while (a < b) { | |
if (b-a == 1) break; | |
if (a%2 == 1) left = merge(left, tree[++a]); | |
if (b%2 == 0) right = merge(tree[--b], right); | |
if (b-a == 1) break; | |
left = merge(left, tree[a+1]); | |
right = merge(tree[b-1], right); | |
a /= 2; b /= 2; | |
} | |
return merge(left, right).max; | |
} | |
int main() | |
{ | |
ios_base::sync_with_stdio(false); cin.tie(NULL); | |
ll N, Q, U, V; cin >> N >> Q >> U >> V; | |
sz = (1 << (ll)ceil(log2(N))); | |
tree.assign(2*sz, {-INF, -INF, -INF, 0}); | |
for (ll i=0; i<N; i++) { | |
ll x; cin >> x; | |
update(i, U*x + V); | |
} | |
while (Q--) { | |
ll op, a, b; cin >> op >> a >> b; | |
if (op == 0) { | |
cout << query(a-1, b-1) - V << '\n'; | |
} | |
if (op == 1) { | |
update(a-1, U*b + V); | |
} | |
} | |
return 0; | |
} |

'✏️ 알고리즘 > PS 기록' 카테고리의 다른 글
[백준 10999번] 구간 합 구하기2 (0) | 2023.04.02 |
---|---|
[백준 10167번] 금광 (2) | 2023.03.30 |
[백준 25639번] 수열과 최대 상승 쿼리 (2) | 2023.03.29 |
[백준 2336번] 굉장한 학생 (2) | 2023.03.27 |
[백준 12015번] 가장 긴 증가하는 부분 수열2 - 세그먼트 트리 (2) | 2023.03.27 |