【BOI2012】Peaks

Description

有一个居住在多山岛屿的登山家,已经攀上了一座山峰,并且要攀爬另外一座更高的山峰。

更精确地说,岛上的每一点都有一个大于零的海拔(海面的海拔为零),并且如果登山家位于海拔Ei的山峰上,那么他的目标是到达其他海拔为Ej(Ej>Ei)的山峰。因为登山家在一个山峰上,所以无法马上向上爬——为了到达一个海拔更高的地点,登山家需要先下山才能上山。下山的路不及上山精彩,因此,登山家想将从当前地点到达更高山峰途中最低点的海拔最大化。

岛屿的地图是一个二维的N*M的矩形网格,并且描述了岛屿每一部分的海拔——格子里的数字表示岛屿对应地区的海拔。如果两个各自有公共点,那么他们相邻。因此,每个格子(除了在边界上的)和其他8个格子相邻。一条路径是一系列的格子,序列中连续的两个格子相邻。一个“平区域”是一个相同海拔格子的集合,并且集合中任意两个格子能够用仅经过这个集合内格子的路径连接。任意两个等高的相邻格子属于同一“平区域” 。一座山峰,是一个相邻的格子中没有更高海拔的“平区域”。

写一个程序,找到所有山峰,并且计算每个山峰到达更高山峰路途中最大的最低海拔。对于岛上最高的山峰(岛上没有更高的山峰),可以确定登山家会离开岛屿寻找更高的山峰,因此,路途中的最低海拔为零(海平面的海拔)。

Input

输入的第一行包含两个整数N和M(1<=N,M<=2000,N*M<=10^5),分别是地图的高和宽。

接下来N行包含岛屿地图的描述。其中每行包含M个空格隔开的整数Eij(1<=Eij<=10^6)。格子Eij(对应地图的i 行j 列)的海拔为输入的i+1行第j 个整数。

Output

输出的第一行须包含一个整数P,岛屿中山峰的个数。接下来P行须每行包含两个整数:这座山峰的海拔及到达更高山峰途中最低点海拔的最大值。这些山峰的信息按照海拔降序输出;如果若干座山峰海拔相同,那么它们按照那个最低点的海拔降序输出。

Sample Input

输入1:

6 6

21 16 9 11 6 7

21 21 10 14 15 9

18 20 8 9 13 14

11 10 9 9 8 13

8 12 12 14 13 8

7 13 12 9 5 1

输入2:

5 3

16 14 16

14 14 15

12 17 16

12 13 10

16 11 16

Sample Output

输出1:

4

21 0

15 11

14 13

13 12

输出2:

5

17 0

16 15

16 14

16 13

16 13

Data Constraint

• 15 分的数据中N<=2或M<=2。

• 50 分的数据中有P<=500。

• 80 分的数据中有P<=5000。

题解

我们可以先把作为峰的合并为一个块,然后其他点每一个都作为一个块
然后按照高度由大到小插入块并且进行合并操作就可以了
但是这题细节很多所以说要耐心实现

var
    stack,cc:array[0..100005]of longint;
    father,big,bt:array[0..200005]of longint;
    go:array[0..9]of longint;
    a,ans:array[0..100005,1..2]of longint;
    bz:array[0..400005]of boolean;
    i,j,k,l,n,m,x,y,z,p,q,max1,max2,s:longint;
    b:boolean;
procedure qsort(l,r:longint);
var
    i,j,mid:longint;
begin
    i:=l;
    j:=r;
    mid:=a[(i+j) div 2,1];
    repeat
        while a[i,1]>mid do inc(i);
        while a[j,1]<mid do dec(j);
        if i<=j then
        begin
            a[0]:=a[i];
            a[i]:=a[j];
            a[j]:=a[0];
            inc(i);
            dec(j);
        end;
    until i>j;
    if i<r then qsort(i,r);
    if l<j then qsort(l,j);
end;
procedure qsort1(l,r:longint);
var
    i,j,mid,midd:longint;
begin
    i:=l;
    j:=r;
    mid:=ans[(i+j) div 2,1];
    midd:=ans[(i+j) div 2,2];
    repeat
        while (ans[i,1]>mid) or ((ans[i,1]=mid) and (ans[i,2]>midd)) do inc(i);
        while (ans[j,1]<mid) or ((ans[j,1]=mid) and (ans[j,2]<midd)) do dec(j);
        if i<=j then
        begin
            ans[0]:=ans[i];
            ans[i]:=ans[j];
            ans[j]:=ans[0];
            inc(i);
            dec(j);
        end;
    until i>j;
    if i<r then qsort1(i,r);
    if l<j then qsort1(l,j);
end;
function getfather(x:longint):longint;
begin
    if father[x]=x then exit(x) else
    father[x]:=getfather(father[x]);
    exit(father[x]);
end;
function check(x,y:longint):boolean;
begin
    if (x-1) mod m=0 then
        if (y=2) or (y=6) or (y=1) then exit(false);
    if x mod m=0 then
        if (y=4) or (y=5) or (y=8) then exit(false);
    exit(true);
end;
begin
    //assign(input,'t4.in'); reset(input);
    assign(input,'peaks.in'); reset(input);
    assign(output,'peaks.out'); rewrite(output);
    readln(n,m);
    for i:=1 to n do
    begin
        for j:=1 to m do
        begin
            inc(p);
            read(a[p,1]);
            a[p,2]:=p;
            if a[p,1]>max1 then max1:=a[p,1];
            cc[p]:=a[p,1];
        end;
        readln;
    end;
    go[1]:=-1; go[2]:=-m-1; go[3]:=-m; go[4]:=-m+1;
    go[5]:=1; go[6]:=m-1; go[7]:=m; go[8]:=m+1;
    qsort(1,p);
    for i:=1 to 2*p do father[i]:=i;
    j:=1;
    for i:=max1 downto 1 do
    begin
        while (j>0) and (a[j,1]=i) do
        begin
            if bz[a[j,2]]=true then
            begin
                inc(j);
                continue;
            end;
            b:=false;
            stack[0]:=1; stack[1]:=a[j,2];
            l:=0;
            bz[a[j,2]]:=true;
            while stack[0]>l do
            begin
                inc(l);
                x:=stack[l];
                for k:=1 to 8 do
                if (go[k]+x>0) and (go[k]+x<=p) then
                begin
                    if check(x,k)=false then continue;
                    y:=go[k]+x;
                    if cc[y]>cc[x] then b:=true;
                    if (cc[y]=cc[x]) and (bz[y]=false) then
                    begin
                        bz[y]:=true;
                        inc(stack[0]);
                        stack[stack[0]]:=y;
                    end;
                end;
            end;
            if b=false then
            begin
                inc(q);
                for k:=1 to stack[0] do
                begin
                    father[stack[k]]:=q+p;
                    big[q+p]:=cc[stack[k]];
                end;
            end;
            inc(j);
        end;
    end;
    z:=0;
    fillchar(bz,sizeof(bz),false);
    for i:=1 to p do
    begin
        if a[i,1]=1742 then
        begin
            a[i,1]:=a[i,1];
        end;
        max2:=0;
        for j:=0 to 8 do
        if (a[i,2]+go[j]>0) and (a[i,2]+go[j]<=p) then
        begin
            if check(a[i,2],j)=false then continue;
            if cc[a[i,2]]>cc[a[i,2]+go[j]] then continue;
            y:=a[i,2]+go[j];
            if big[getfather(y)]>=max2 then
            begin
                l:=getfather(y);
                max2:=big[l];
                if (cc[y]=max1) and (bz[l]=false) then
                begin
                    bz[l]:=true;
                    inc(z);
                    ans[z,1]:=cc[y]; ans[z,2]:=0;
                end;
            end;
        end;
        y:=l;
        for k:=0 to 8 do
        if (a[i,2]+go[k]>0) and (a[i,2]+go[k]<=p) then
        begin
            if cc[a[i,2]]>cc[a[i,2]+go[k]] then continue;
            if check(a[i,2],k)=false then continue;
            x:=getfather(a[i,2]+go[k]);
            if x<>y then
            begin
                if (bz[x]=false) and (x>p) and (big[x]<big[y]) then
                begin
                    if a[i,1]=735 then
                    begin
                        a[i,1]:=a[i,1];
                    end;
                    bz[x]:=true;
                    for s:=z+1 to z+bt[x]+1 do
                    begin
                        ans[s,1]:=big[x];
                        ans[s,2]:=a[i,1];
                    end;
                    inc(z,bt[x]+1);
                    if a[i,1]=1742 then
                    begin
                        a[i,1]:=a[i,1];
                    end;
                end else if big[x]=big[y] then
                begin
                inc(bt[y],bt[x]+1);
                end;
                father[x]:=y;
            end;
        end;
    end;
    qsort1(1,z);
    writeln(z);
    for i:=1 to z do writeln(ans[i,1],' ',ans[i,2]);
    close(input); close(output);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值