포스트

BOJ 25639 수열과 최대 상승 쿼리

sorohue가 PS하는 블로그

BOJ 25639 수열과 최대 상승 쿼리

문제 링크입니다.

수열 나누기

수열 전체를 적당히 둘로 쪼개면, 그 두 조각에 걸쳐서 상승할 수 있는 최댓값은 오른쪽 조각의 최댓값 - 왼쪽 조각의 최솟값입니다. 나머지 경우는 왼쪽 조각 안에서의 최대 상승 값과, 오른쪽 조각 안에서의 최대 상승 값을 구해 주면 되겠네요. 셋 중 가장 큰 값이 정답이 되고, 각 조각에서의 최대 상승 값은 마찬가지로 그 조각을 둘로 쪼갠 뒤에 구할 수 있습니다.

자구 비빔밥

단일 값을 변경하는 업데이트가 주어집니다. 구간 최솟값/최댓값/최대 상승값을 관리하는 세그먼트 트리를 만들어 업데이트와 쿼리를 각각 $\mathcal{O}(\log N)$, $\mathcal{O}(1)$에 처리해 줍시다.

코드

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
#include<bits/stdc++.h>
#define mid (l+r>>1)
using namespace std;
using ll = long long;
struct node{
	int mn, mx, ans;
};

node tree[404040];

void upd(int now, int l, int r, int i, int v){
	if(i < l || r < i) return;
	if(l == r){
		tree[now].mn = tree[now].mx = v;
		tree[now].ans = 0;
		return;
	}
	upd(now<<1, l, mid, i, v);
	upd(now<<1|1, mid+1, r, i, v);
	tree[now].mn = min(tree[now<<1].mn, tree[now<<1|1].mn);
	tree[now].mx = max(tree[now<<1].mx, tree[now<<1|1].mx);
	tree[now].ans = max({tree[now<<1].ans, tree[now<<1|1].ans, tree[now<<1|1].mx-tree[now<<1].mn});
	return;
}

node qry(int now, int l, int r, int L, int R){
	if(l > R || L > r) return {1000000007, -1000000007, 0};
	if(L <= l && r <= R) return tree[now];
	node lt = qry(now<<1, l, mid, L, R);
	node rt = qry(now<<1|1, mid+1, r, L, R);
	return {min(lt.mn, rt.mn), max(lt.mx, rt.mx), max({lt.ans, rt.ans, rt.mx-lt.mn})};
}

int main(){
	cin.tie(0);cout.tie(0);ios::sync_with_stdio(false);
	int n; cin >> n; for(int i = 1; i <= n; i++){
		int a; cin >> a; upd(1, 1, n, i, a);
	}
	int Q; cin >> Q; while(Q--){
		int q; cin >> q;
		if(q == 1){
			int k, x; cin >> k >> x; upd(1, 1, n, k, x);
		}
		if(q == 2){
			int L, R; cin >> L >> R; cout << qry(1, 1, n, L, R).ans << '\n';
		}
	}
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.