티스토리 뷰
[BOJ 1725] 히스토그램 - P5
문제 요약
히스토그램에서 만들 수 있는 직사각형 중에서 가장 큰 넓이를 찾는 문제이다.
문제 풀이
직사각형의 넓이는 (r - l + 1) * getMin(l,r) 로 구할 수 있다. 여기서 문제는 N = 10만이므로 l,r을 전탐색으로 돌리면 시간이 초과하게 된다.
해결 방법은 세그먼트 트리에 가장 작은 값의 인덱스를 저장해놓는 것이다. 그래서 퀵소트가 작동하는 방식처럼 매 [l,r]구간에서 가장 작은 값의 인덱스를 찾아서 넓이를 구한 다음, 그 인덱스를 기준으로 좌, 우를 갈라서 똑같이 재귀적으로 넓이를 구해주면 된다.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int SIZE = 100009;
const int INF_IDX = 0;
int tree[SIZE*8],h[SIZE];
int startIdx = 1;
int makeTree(int node){
if(node >= startIdx) return tree[node];
int lChild = node*2, rChild = node*2+1;
if(h[makeTree(lChild)] > h[makeTree(rChild)]) tree[node] = tree[rChild];
else tree[node] = tree[lChild];
return tree[node];
}
int getSmallestIdx(int node,int cl,int cr,int ql,int qr){
if(ql > cr || cl > qr) return INF_IDX;
if(qr >= cr && ql <= cl) return tree[node];
int mid = (cl+cr)/2;
int leftIdx = getSmallestIdx(node*2,cl,mid,ql,qr),
rightIdx = getSmallestIdx(node*2+1,mid+1,cr,ql,qr);
if(h[leftIdx] > h[rightIdx]) return rightIdx;
else return leftIdx;
}
ll getMaxArea(int l,int r){
if(l > r) return 0;
int curIdx = getSmallestIdx(1,1,startIdx,l,r);
ll curArea = 1LL * h[curIdx] * (r - l + 1);
ll leftArea = getMaxArea(l, curIdx - 1), rightArea = getMaxArea(curIdx + 1, r);
return max({curArea,leftArea,rightArea});
}
int main(){
int n; scanf("%d",&n);
tree[0] = 0;
h[INF_IDX] = 2e9;
for(;startIdx < n ; startIdx *= 2);
for(int i=1 ; i<=n ; i++){
scanf("%d",&h[i]);
tree[startIdx + i -1] = i;
}
makeTree(1);
printf("%lld\n",getMaxArea(1,n));
return 0;
}
'Problem Solving > Segment Tree' 카테고리의 다른 글
[BOJ 11658]구간 합 구하기3 (0) | 2021.11.13 |
---|---|
[BOJ 2243] 사탕 상자, [BOJ 9426] 중앙값 측정 (0) | 2021.10.29 |
[BOJ 1517] 버블 소트 (0) | 2021.10.21 |
[CF 1042D] Petya and Array (0) | 2021.10.21 |
[BOJ 7469] K번째 수 (0) | 2021.10.20 |
댓글