ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [6549] 히스토그램에서 가장 큰 직사각형
    BOJ 2021. 8. 30. 21:42

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

     

    6549번: 히스토그램에서 가장 큰 직사각형

    입력은 테스트 케이스 여러 개로 이루어져 있다. 각 테스트 케이스는 한 줄로 이루어져 있고, 직사각형의 수 n이 가장 처음으로 주어진다. (1 ≤ n ≤ 100,000) 그 다음 n개의 정수 h1, ..., hn (0 ≤ hi ≤

    www.acmicpc.net

    <문제>

    세그먼트 트리를 이용했다.

    리프노드에는 각 직사각형의 높이를 저장하고, 리프노드가 아니라면 구간중 가장 작은 높이를 저장한다.

    end-start+1이 느리게 갱신되는 세그먼트 트리랑 겹치는 부분이 있지만 이 문제는 lazy propagation은 아니고,

    구간중 가장 짧은 높이는 세그먼트 트리로, end-start+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
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    #include<stdio.h>
    #include<math.h>
    #include<vector>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    int n;
    int num[100001];
    vector <int>segTree;
    void makeSegTree(int node, int start, int end) {
        if (start == end) {
            segTree[node] = start;
            return;
        }
        int mid = (start + end/ 2;
        makeSegTree(node * 2, start, mid);
        makeSegTree(node * 2 + 1, mid + 1end);
        if (num[segTree[node * 2]] <= num[segTree[node * 2 + 1]]) {
            segTree[node] = segTree[node * 2];
        }
        else {
            segTree[node] = segTree[node * 2 + 1];
        }
    }
    int findIdx(int node, int start, int endint left, int right) {
        if (left > end || right < start) return -1;
        if (left <= start && end <= right)return segTree[node];
     
        int mid = (start + end/ 2;
        int leftRes = findIdx(node * 2, start, mid, left, right);
        int rightRes = findIdx(node * 2 + 1, mid + 1end, left, right);
        if (leftRes == -1)
            return rightRes;
        if (rightRes == -1)
            return leftRes;
        if (num[leftRes] <= num[rightRes])
            return leftRes;
        else
            return rightRes;
    }
    ll solve(int start, int end) {
        int numSize = n;
        int m = findIdx(10, numSize-1, start, end);
        ll area = (ll)(end - start + 1* (ll)num[m];
     
        if (start <= m - 1) {
            ll tmp = solve(start, m - 1);
            area = max(tmp, area);
        }
        if (m + 1 <= end) {
            ll tmp = solve(m + 1end);
            area = max(tmp, area);
        }
        return area;
    }
    int main(void) {
        while (1) {
            scanf("%d"&n);
            if (n == 0)break;
            for (int i = 0; i < n; i++)
                scanf("%d"&num[i]);
     
            int treeHeight = (int)ceil(log2(n));
            int treeSize = (1 << (treeHeight + 1));
            segTree.resize(treeSize);
            makeSegTree(10, n - 1);
     
            printf("%lld\n", solve(0, n - 1));
            segTree.clear();
        }
        return 0;
    }
     
    cs

     

    'BOJ' 카테고리의 다른 글

    [2206] 벽 부수고 이동하기  (0) 2021.08.30
    [14428] 수열과 쿼리 16  (0) 2021.08.30
    [15685] 드래곤 커브  (0) 2021.08.30
    [10451] 순열 사이클  (0) 2021.08.30
    [1303] 전쟁 - 전투  (0) 2021.08.30

    댓글