Problem:
日本沈没 (Japan Sinks)

問題文

日本列島は細長い列島である．日本列島は平行な境界線により N 個の区画に分けられている．区画には端から順に 1 から N の番号が付けられている．区画 i (1 ≦ i ≦ N) の高さは A_i である．

日本列島は海に囲まれており，海面の高さは場所によらず一定である．高さが海面の高さより高い区画を陸地と呼ぶ．

陸地が連続している部分のことを島と呼ぶ．より正確に書くと以下の通りである．整数 l, r (1 ≦ l ≦ r ≦ N) について，日本列島のうち区画 l，区画 l+1，...，区画 r からなる部分を領域 [l, r] という．以下の条件を満たす領域 [l, r] を島という：

区画 l，区画 l+1，...，区画 r はすべて陸地である．

l>1 ならば区画 l-1 は陸地ではない．

r<N ならば区画 r+1 は陸地ではない．

海面の上昇により，日本列島は少しずつ沈没している．現在の海面の高さは 0 であるが，これは時間が経つにつれて徐々に上がり，ついには日本全体が海になってしまう．

JOI 君は，海面の高さが上昇すると，日本の島の数が増減することに気付いた．現在から，日本に陸地がなくなるまでの間 (現在も含む) における，島の数の最大値を求めたい．

制約

1 ≦ N ≦ 100000 (= 10^5)

0 ≦ A_i ≦ 1000000000 (= 10^9) (1 ≦ i ≦ N)

入力・出力

入力

入力は以下の形式で標準入力から与えられる．

N

A_1 A_2 ... A_N

出力

現在から，日本に陸地がなくなるまでの間 (現在も含む) における，島の数の最大値を 1 行で出力せよ．

入出力例

入力例 1

6
0 1 2 1 3 2

出力例 1

2

海面の高さが 0 以上 1 未満のとき，区画 2, 3, 4, 5, 6 が陸地である．領域 [2, 6] が唯一の島なので，島の数は 1 である．

海面の高さが 1 以上 2 未満のとき，区画 3, 5, 6 が陸地である．領域 [3, 3] と領域 [5, 6] が島なので，島の数は 2 である．

海面の高さが 2 以上 3 未満のとき，区画 5 のみが陸地である．領域 [5, 5] が唯一の島なので，島の数は 1 である．

海面の高さが 3 になると，陸地はなくなり，島の数は 0 になる．

よって島の数の最大値は 2 なので，2 を出力する．

入力例 2

6
3 2 3 0 2 0

出力例 2

2

海面の高さが 0 以上 2 未満のとき，区画 1, 2, 3, 5 が陸地である．領域 [1, 3] と領域 [5, 5] が島なので，島の数は 2 である．

海面の高さが 2 以上 3 未満のとき，区画 1, 3 が陸地である．領域 [1, 1] と領域 [3, 3] が島なので，島の数は 2 である．

海面の高さが 3 になると，陸地はなくなり，島の数は 0 になる．

よって島の数の最大値は 2 なので，2 を出力する．

入力例 3

10
4 1 2 1 2 3 5 4 3 2

出力例 3

3

情報オリンピック日本委員会作 『第 18 回日本情報オリンピック JOI 2018/2019 予選競技課題』

Solution in C (judge verdict: Accepted)

#include <stdio.h>
#include "stdlib.h"

#define MAXN 100000

typedef uint bool;

typedef struct{
    uint height;//海拔
    uint index;//序号
    bool hasProbed;//记录其是否被检查过
}area,*areaptr;


typedef struct {
    areaptr *content;
    size_t len;
}max_heap;

static area input[MAXN];
static size_t N;

void new_max_heap(size_t len,area input[len],max_heap* out){
    out->content=(areaptr*)malloc(sizeof(areaptr)*len);
    out->len=len;

    for (uint i=0;i<len;i++) out->content[i]=input+i;

    for (uint i=len;i>=1;i--){

        //TODO 修正健堆
        for(uint cur=i;cur<=len;){
            uint cur_height=out->content[cur-1]->height;
            uint left_child=cur*2,right_child=left_child+1;

            if(right_child<=len){
                uint max_index=out->content[left_child-1]->height>out->content[right_child-1]->height?left_child:right_child;
                if(out->content[max_index-1]->height>=out->content[cur-1]->height){
                    areaptr temp=out->content[cur-1];
                    out->content[cur-1]=out->content[max_index-1];
                    out->content[max_index-1]=temp;
                    cur=max_index;
                }else{
                    break;
                }
            }else if (left_child<=len){
                //若左子节点海拔高
                if(out->content[left_child-1]->height>=out->content[cur-1]->height){
                    areaptr temp=out->content[cur-1];
                    out->content[cur-1]=out->content[left_child-1];
                    out->content[left_child-1]=temp;
                    cur=left_child;
                }else{
                    break;
                }
            }else
                break;
        }
    }
}

areaptr get_max(max_heap* self){
    return self->content[0];
}

areaptr extract_max(max_heap* self){
    areaptr ret=self->content[0];

    //交换首位
    self->content[0]=self->content[--self->len];

    uint cur=1;
    while(cur<self->len){
        uint left_child=cur*2,right_child=left_child+1;

        if(right_child<=self->len){
            uint max_index=self->content[left_child-1]->height>self->content[right_child-1]->height?left_child:right_child;
            if(self->content[max_index-1]->height>=self->content[cur-1]->height){
                areaptr temp=self->content[cur-1];
                self->content[cur-1]=self->content[max_index-1];
                self->content[max_index-1]=temp;
                cur=max_index;
            }else{
                break;
            }
        }else if (left_child<=self->len){
            //若左子节点海拔高
            if(self->content[left_child-1]->height>=self->content[cur-1]->height){
                   areaptr temp=self->content[cur-1];
                   self->content[cur-1]=self->content[left_child-1];
                   self->content[left_child-1]=temp;
                   cur=left_child;
            }else{
                break;
            }
        }else{
            break;//当前节点没有子节点时则结束
        }


    }

    return ret;
}

void show_heap(max_heap* self){
    for (int i=0;i<self->len;i++)
        printf("%d ",self->content[i]->height);
}

bool is_empty(max_heap* self){
    return self->len==0;
}

//TODO:处理全岛均在海平线之下的情况
int main() {
    max_heap heap;
    uint max_island_num=0,cur_island_num=max_island_num;

    //获得输入，并初始化堆
    scanf("%lu",&N);

    for(uint i=0;i<N;i++) {
        uint height;
        scanf("%u",&height);
        input[i].height=height;
        input[i].index=i;
        input[i].hasProbed=0;
    }

    if(N==1){
        if(input[0].height==0)
            puts("0");
        else
            puts("1");
        return 0;
    }

    //以下均建立在N不为1的基础上
    new_max_heap(N,input,&heap);

    //根据海拔从高到低扫描扫描各区域
    while(!is_empty(&heap)){
        //当前拓展的登高线高度
        uint current_height=get_max(&heap)->height;

        if (current_height==0)
            break;

        //对当前等高线进行扫描,以更新岛屿数
        while(!is_empty(&heap)&&current_height==get_max(&heap)->height){
            areaptr cur_area=extract_max(&heap);
            uint cur_index=cur_area->index;

            //printf("%d ",cur_index);

            //若当前区域在最左侧
            if(cur_index==0){
                if(!input[cur_index+1].hasProbed)
                    cur_island_num++;
            }else if(cur_index==N-1){
                if(!input[cur_index-1].hasProbed)
                    cur_island_num++;
            }else{
                if(input[cur_index+1].hasProbed==input[cur_index-1].hasProbed)
                    if(input[cur_index+1].hasProbed)//若两侧均检查过
                        cur_island_num--;
                    else
                        cur_island_num++;
            }

            cur_area->hasProbed=1;
        }

        max_island_num=max_island_num<cur_island_num?cur_island_num:max_island_num;

    }

    printf("%u\n",max_island_num);


    return 0;
}