본문 바로가기

BOJ

[BOJ 1725] 히스토그램

https://www.acmicpc.net/problem/1725

 

1725번: 히스토그램

첫 행에는 N (1 ≤ N ≤ 100,000) 이 주어진다. N은 히스토그램의 가로 칸의 수이다. 다음 N 행에 걸쳐 각 칸의 높이가 왼쪽에서부터 차례대로 주어진다. 각 칸의 높이는 1,000,000,000보다 작거나 같은

www.acmicpc.net

Tag : DSU

 

풀이

히스토그램은 모노톤 큐, 분할정복, 세그먼트 트리 풀이가 있다는 것이 잘 알려진 문제입니다.

이 히스토그램을 유니온 파인드로도 풀 수 있는데 저는 이 풀이가 가장 쉽고 구현도 편한다고 생각합니다.

 

일단 (a[i], i)를 관리하는 벡터 v를 만들고 이를 내림차순으로 정렬합니다. 

그리고 이를 순회하며 a[i - 1], a[i + 1]을 보며 a[i] 이상인 경우 merge해줍니다.

그러면 i와 merge된 원소들은 항상 a[i] 이상의 값을 가지고 있으며 인접한 원소들을 통해 묶이게됩니다.

이 상태에서 sz[find(i)]와 a[i]를 통해 a[i]가 히스토그램에서 가장 낮은 원소일 경우의 최대를 구할 수 있고

이를 모든 원소에 반복해보면 답을 구할 수 있습니다.

 

전체코드

#include "bits/stdc++.h"
#define endl '\n'

using namespace std;
using ll = long long;

int n;
int a[101010];
int pa[101010];
int sz[101010];

int find(int a) {
    if(a == pa[a]) return a;
    else return pa[a] = find(pa[a]);
}

void merge(int a, int b) {
    a = find(a); b = find(b);
    if(a == b) return;
    if(sz[a] < sz[b]) swap(a, b);
    sz[a] += sz[b];
    pa[b] = a;
}

int main() {
    ios::sync_with_stdio(0); cin.tie(0);
//    freopen("input.txt", "r", stdin);
    
    cin >> n;
    vector<pair<int, int>> v(n);
    for(int i=1; i<=n; i++) {
        cin >> a[i];
        v[i - 1] = {a[i], i};
        pa[i] = i;
        sz[i] = 1;
    }
    sort(v.begin(), v.end(), greater<>());
    ll ans = 0;
    for(auto &[x, idx] : v) {
        if(idx >= 2 and a[idx - 1] >= x) merge(idx, idx - 1);
        if(idx < n and a[idx + 1] >= x) merge(idx, idx + 1);
        ans = max(ans, 1ll * x * sz[find(idx)]);
    }
    cout << ans << endl;
}

'BOJ' 카테고리의 다른 글

[BOJ 16583] Boomerangs  (0) 2022.02.09
[BOJ 12858] Range GCD  (1) 2022.02.01
[BOJ 2042] 구간 합 구하기  (0) 2022.01.18
[BOJ 8903] 장비  (0) 2022.01.13
[BOJ 16474] 이상한 전깃줄  (0) 2022.01.13