╰( ̄▽ ̄)╭

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

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

例如,如果岛屿的轮廓如图中所示,并且登山家在海拔为E4的山峰,那么有三个山峰有更高的海拔(E5,E6和E7),但是路途中最低点最高的路径是到达海拔E7的山峰的路径——在路上他不会走到海拔E2以下(在其他路径中他必须经过海拔E1的地点)。如果他从海拔E5的山峰出发,那么对应路径经过的最低海拔为E3(到达E6的路径),但是如果他从E6 出发,那么最低点就是E1。

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

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

1<=N,M<=2000,N∗M<=105,1<=Eij<=106

(⊙ ▽ ⊙)

先把网格按高度从大到小排序

然后依次插入网格。

每次插入网格C后,询问其相邻的网格;

若其相邻的网格存在已被访问过的,那么这个网格所在的“平区域”肯定不是峰;

同时可以更新其相邻的网格所在的峰的答案。

否则C就是峰。


细节很多,特判很多,出题人是SB

( ̄~ ̄)

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#define ll long long
#define pos(x,y) (((x)-1)*m+(y))
using namespace std;
const char* fin="peaks.in";
const char* fout="peaks.out";
const int inf=0x7fffffff;
const int maxn=100007,maxm=2006;
const int f[8][2]={{0,1},{1,1},{1,0},{-1,0},{-1,-1},{0,-1},{1,-1},{-1,1}};
int n,m,i,j,k,tot,xx;
int a[maxm][maxm],rf[maxm][maxm],go[maxm*maxm],Rf[maxm*maxm];
bool bz[maxm][maxm];
int dad[maxn];
int ans1;
struct node{
int x,y,z,ans;
int feng;
}b[maxn],ans[maxn];
bool cmp(const node &a,const node &b){
return a.z>b.z || (a.z==b.z && a.x<b.x) || (a.z==b.z && a.x==b.x && a.y<b.y);
}
bool cmp1(node a,node b){
return a.feng>b.feng || (a.feng==b.feng && a.z>b.z) || (a.feng==b.feng && a.z==b.z && a.ans>b.ans);
}
bool cmp2(node a,node b){
return a.x>b.x || (a.x==b.x && a.y>b.y);
}
int getdad(int v){
if (!dad[v]) return v;
dad[v]=getdad(dad[v]);
return dad[v];
}
int getgo(int v){
if (!go[v]) return v;
go[v]=getgo(go[v]);
return go[v];
}
void merge(int v,int u){
int j=getdad(v),k=getdad(u);
dad[j]=k;
}
int main(){
freopen(fin,"r",stdin);
freopen(fout,"w",stdout);
scanf("%d%d",&n,&m);
k=0;
for (i=1;i<=n;i++) for (j=1;j<=m;j++){
scanf("%d",&a[i][j]);
b[++tot].x=i;
b[tot].y=j;
b[tot].z=a[i][j];
}
sort(b+1,b+tot+1,cmp);
for (i=1;i<=tot;i++) rf[b[i].x][b[i].y]=i;
for (i=1;i<=tot;i++){
b[i].feng=1;
for (j=0;j<8;j++){
int X=b[i].x+f[j][0],Y=b[i].y+f[j][1];
if (X>0 && X<=n && Y>0 && Y<=m){
if (bz[X][Y]){
b[i].feng=0;
int tmp=getdad(rf[b[i].x][b[i].y]);
int tmd=getdad(rf[X][Y]);
if (b[tmp].z>b[tmd].z){
if (tmp!=tmd){
dad[tmd]=tmp;
b[tmd].ans=max(b[tmd].ans,b[i].z);
}
}else{
if (tmp!=tmd){
dad[tmp]=tmd;
if (b[tmp].z!=b[tmd].z){
b[tmp].ans=max(b[tmp].ans,b[i].z);
}else{
if (b[i].z==b[tmp].z) b[tmp].feng=0;
go[pos(b[tmp].x,b[tmp].y)]=pos(b[tmd].x,b[tmd].y);
}
}
}
}
}
}
bz[b[i].x][b[i].y]=true;
}
sort(b+1,b+tot+1,cmp1);
for (i=1;i<=tot;i++) Rf[pos(b[i].x,b[i].y)]=i;
for (i=1;i<=tot;i++){
if (!b[i].feng) break;
if (b[i].z==b[Rf[getgo(pos(b[i].x,b[i].y))]].ans){
continue;
}
ans1++;
ans[ans1].x=b[i].z;
ans[ans1].y=b[Rf[getgo(pos(b[i].x,b[i].y))]].ans;
}
sort(ans+1,ans+ans1+1,cmp2);
printf("%d\n",ans1);
for (i=1;i<=ans1;i++) printf("%d %d\n",ans[i].x,ans[i].y);
return 0;
}

(⊙v⊙)

关键点:

1.把网格按高度从大到小排序

由于要求最小值的最大值,又可以通过单个网格来更新答案;

所以可以采用排序的方法。

【JZOJ3635】【BOI2012】Peaks的更多相关文章

  1. 【疯狂造轮子-iOS】JSON转Model系列之二

    [疯狂造轮子-iOS]JSON转Model系列之二 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇<[疯狂造轮子-iOS]JSON转Model系列之一> ...

  2. 【疯狂造轮子-iOS】JSON转Model系列之一

    [疯狂造轮子-iOS]JSON转Model系列之一 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 之前一直看别人的源码,虽然对自己提升比较大,但毕竟不是自己写的,很容易遗 ...

  3. 【原创分享·支付宝支付】HBuilder打包APP调用支付宝客户端支付

    前言 最近有点空余时间,所以,就研究了一下APP支付.前面很早就搞完APP的微信支付了,但是由于时间上和应用上的情况,支付宝一直没空去研究.然后等我空了的时候,发现支付宝居然升级了支付逻辑,虽然目前还 ...

  4. 【AutoMapper官方文档】DTO与Domin Model相互转换(上)

    写在前面 AutoMapper目录: [AutoMapper官方文档]DTO与Domin Model相互转换(上) [AutoMapper官方文档]DTO与Domin Model相互转换(中) [Au ...

  5. 【Win 10 应用开发】应用预启动

    所谓预启动,其实你一看那名字就知道是啥意思了,这是直接译,也找不到比这个叫法更简练的词了.在系统资源允许的情况下(比如电池电量充足,有足够的内存空间),系统会把用户常用的应用程序在后台启动,但不会显示 ...

  6. 【Win 10 应用开发】启动远程设备上的应用

    这个功能必须在“红石-1”(build 14393)以上的系统版中才能使用,运行在一台设备上的应用,可以通过URI来启动另一台设备上的应用.激活远程应用需要以下前提: 系统必须是build 14393 ...

  7. 【开源】分享2011-2015年全国城市历史天气数据库【Sqlite+C#访问程序】

    由于个人研究需要,需要采集天气历史数据,前一篇文章:C#+HtmlAgilityPack+XPath带你采集数据(以采集天气数据为例子),介绍了基本的采集思路和核心代码,经过1个星期的采集,历史数据库 ...

  8. 【原创分享·微信支付】C# MVC 微信支付教程系列之现金红包

            微信支付教程系列之现金红包           最近最弄这个微信支付的功能,然后扫码.公众号支付,这些都做了,闲着无聊,就看了看微信支付的其他功能,发现还有一个叫“现金红包”的玩意,想 ...

  9. 【原创分享·微信支付】 C# MVC 微信支付教程系列之扫码支付

    微信支付教程系列之扫码支付                  今天,我们来一起探讨一下这个微信扫码支付.何为扫码支付呢?这里面,扫的码就是二维码了,就是我们经常扫一扫的那种二维码图片,例如,我们自己添 ...

  10. 【原创分享·微信支付】 C# MVC 微信支付教程系列之公众号支付

    微信支付教程系列之公众号支付         今天,我们接着讲微信支付的系列教程,前面,我们讲了这个微信红包和扫码支付.现在,我们讲讲这个公众号支付.公众号支付的应用环境常见的用户通过公众号,然后再通 ...

随机推荐

  1. 使用Colaboratory的免费GPU训练神经网络

    1 Colaboratory 介绍 Colaboratory 是一个 Google 研究项目,旨在帮助传播机器学习培训和研究成果.它是一个 Jupyter 笔记本环境,不需要进行任何设置就可以使用,并 ...

  2. 【机器学习】机器学习入门01 - kNN算法

    0. 写在前面 近日加入了一个机器学习的学习小组,每周按照学习计划学习一个机器学习的小专题.笔者恰好近来计划深入学习Python,刚刚熟悉了其基本的语法知识(主要是与C系语言的差别),决定以此作为对P ...

  3. Java基础知识(多线程和线程池)

    新建状态: 一个新产生的线程从新状态开始了它的生命周期.它保持这个状态直到程序 start 这个线程. 运行状态:当一个新状态的线程被 start 以后,线程就变成可运行状态,一个线程在此状态下被认为 ...

  4. mac版pycharm的字体和行间距设置

  5. PHP--通用化API接口数据输出 封装

    /** * 通用化API接口数据输出 * author qinpeizhou * @param $message * @param array $data * @param int $httpCode ...

  6. Java操作Mysql笔记

    第一步,需要下载JDBC驱动, 点我.然后选择合适的版本即可. 下载完成之后解压,然后将mysql-connector-java-5.1.6-bin.jar文件放到java的安装目录下面. 这里每个人 ...

  7. Web前后端缓存技术(缓存的主要作用是什么)

    Web前后端缓存技术Web前后端缓存技术(缓存的主要作用是什么) 一.总结 一句话总结: 加快页面打开速度 减少网络带宽消耗 降低服务器压力 1.在Web应用中,应用缓存的地方有哪些? 主要有浏览器缓 ...

  8. springboot核心技术(四)-----Docker、数据访问、自定义starter

    Docker 1.简介 Docker是一个开源的应用容器引擎:是一个轻量级容器技术: Docker支持将软件编译成一个镜像:然后在镜像中各种软件做好配置,将镜像发布出去,其他使用者可以直接使 用这个镜 ...

  9. hibernate 一对一注解

    bi如 用户的阅读历史和文章表是单向一对一关系, 阅读历史中通过deviceId外键关联文章表的主键 然后,再从getter setter上进行注解 @OneToOne(cascade = Casca ...

  10. ArrayList基础知识

    ArrayList简介 ArrayList 的底层是数组队列,相当于动态数组.与 Java 中的数组相比,它的容量能动态增长.在添加大量元素前,应用程序可以使用ensureCapacity操作来增加 ...