오늘은 세그 미는날~~
평범한 최솟값 세그가 아니여서 좀 고생했다.
6549번: 히스토그램에서 가장 큰 직사각형
입력은 테스트 케이스 여러 개로 이루어져 있다. 각 테스트 케이스는 한 줄로 이루어져 있고, 직사각형의 수 n이 가장 처음으로 주어진다. (1 ≤ n ≤ 100,000) 그 다음 n개의 정수 h1, ..., hn (0 ≤ hi ≤
www.acmicpc.net
이 문제의 핵심은
세그트리가 반환해주는 값이 구간 내의 히스토그램 값의 최솟값 이 아니라,
히스토그램이 최솟값을 가지는 곳의 인덱스값이다.
이를 위해 세그트리를 살짝 수정해 준 뒤에,
구간에서의 최대값을 찾을때에는 분할정복을 이용해주었다.
분할을 할때는 반드시 딱 절반에서 나누는 것이 아니라,
구간 내에서의 최솟값을 찾아서
최솟값 인덱스+1 ~ 끝
시작 ~ 최솟값 인덱스-1
이렇게 비교해주면 AC를 받을 수 있다.
이 구간 내에서의 최솟값을 빨리 찾기 위해 세그멘트 트리를 사용해주었다.
더보기
#include <bits/stdc++.h>
#define INF 123456789123456789LL
using namespace std;
typedef long long int ll;
ll arr[123456] = {0};
ll seg[456789] = {0};
int n;
int init(int node=1, int start=1, int end=n){
if(start == end) return seg[node] = start;
int mid = (start + end) / 2;
int a = init(node*2, start, mid);
int b = init(node*2+1, mid+1, end);
return seg[node] = arr[a]<=arr[b] ? a:b;
}
int query(int l, int r, int node=1, int start=1, int end=n){
if(r < start || l > end) return 0;
if(l <= start && end <= r) return seg[node];
int mid = (start + end) / 2;
int a = query(l, r, node*2, start, mid);
int b = query(l, r, node*2+1, mid+1, end);
return arr[a] <= arr[b] ? a:b;
}
ll search(int s, int e){
if(s==e) return arr[s];
int idx = query(s,e);
ll ret = (ll)arr[idx] * (e-s+1);
if(idx > s){ ret = max(ret, search(s,idx-1)); }
if(idx < e){ ret = max(ret, search(idx+1,e)); }
return ret;
}
int main(){
arr[0] = INF;
scanf("%d", &n);
for(int i=1; i<=n; i++) scanf("%d", &arr[i]);
init();
printf("%lld\n", search(1,n));
return 0;
}
여담으로,
위 문제의 살짝 변형된 버전의 문제가 존재하므로
빨리 가서 날먹하고 오도록 하자
1725번: 히스토그램
첫 행에는 N (1 ≤ N ≤ 100,000) 이 주어진다. N은 히스토그램의 가로 칸의 수이다. 다음 N 행에 걸쳐 각 칸의 높이가 왼쪽에서부터 차례대로 주어진다. 각 칸의 높이는 1,000,000,000보다 작거나 같은
www.acmicpc.net
반응형