Description

有这样一块土地,它可以被划分成N×M个正方形小块,每块面积是一平方英寸,第i行第j列的小块可以表示成P(i,j)。这块土地高低不平,每一小块地P(i,j)都有自己的高度H(i,j)(单位是英寸)。

一场倾盆大雨后,这块地由于地势高低不同,许多低洼地方都积存了不少降水。假如你已经知道这块土地的详细信息,你能求出它最多能积存多少立方英寸的降水么?

 

Input

输入文件第一行有两个数,N,M(1<=N, M <=100),表示土地的规模是N×M平方英寸。

以下有N行,每行有M个整数,表示每块地的高低(每个整数在[1,10000]内,以英寸为单位)。

 

Output

输出文件只有一行,一个数,表示土地中最多能积存多少立方英寸的水。

 

Sample Input

3 6
3 3 4 4 4 2
3 1 3 2 1 4
7 3 1 6 4 1

Sample Output

5

HINT

​传送门​

考试竟然考了这道的原题= =优化加错了结果竟然考试里还A了= =


一个很简单的想法是,每次找出最小高度的点,

然后向四周扩展到极点,并且确定出它能上升的最大高度,并且填满;

如何扩展?只要用个BFS,每次向四周值相等的位置扩展即可;

对于某一个位置,确定它上升的幅度可以重新BFS一遍。。

那么知道了每个位置最后变成了什么样,就可以知道变化量了,累加即可。。

注意边界都是0。。

感觉有点说不清楚,不过可以看代码之类的吧。。=v=


那么在最坏O((NM)^2*log(NM))的时间内可以解决这道题,,

显然数据如果精心构造,也就是N*M个数全部都相等,那么每次都要BFS完整的一遍,

于是花式TLE了……

怎么解决呢……我们可以用一个vis[x][y]来加速。

假设一遍BFS之后,我们发现水没有任何上涨,

那就再重新跑一遍,并且走过的所有的点(x,y),vis[x][y]=1。


这样子的话我们看到,确实这种数据可以AC了,但是时间复杂度保证了吗?

其实是可以证明的,在最坏的情况下,时间复杂度也是可观的;

常数当然大,,因为无故多跑了一遍bfs……


事实上这题正规点的做法都是SPFA之类的……

可以百度。

毕竟我这种做法还是很玄学的……






#include<bits/stdc++.h>
using namespace std;
const int
N=105,
inf=20000;
int n,m,ans,tag;
int b[N][N],a[N][N],flag[N][N];
bool vis[N][N];

struct node{int high,x,y;};
priority_queue<node>Heap;
bool operator <(node a,node b){return a.high>b.high;}
bool operator >(node a,node b){return a.high<b.high;}

struct QUEUE{int x,y;}Q[N*N];
void BFS(int xstart,int ystart,int num,int f){
int head=0,tail=1;
Q[0]=(QUEUE){xstart,ystart};
flag[xstart][ystart]=tag;
while (head<tail){
int x=Q[head].x,y=Q[head++].y;
if (f) vis[x][y]=1;
if (a[x-1][y]!=num) ans=min(ans,a[x-1][y]);
if (a[x+1][y]!=num) ans=min(ans,a[x+1][y]);
if (a[x][y-1]!=num) ans=min(ans,a[x][y-1]);
if (a[x][y+1]!=num) ans=min(ans,a[x][y+1]);
if (x==1 && num>=0) ans=0;
if (y==1 && num>=0) ans=0;
if (x==n && num>=0) ans=0;
if (y==m && num>=0) ans=0;

if (x>1 && flag[x-1][y]!=tag && a[x-1][y]==num) flag[x-1][y]=tag,Q[tail++]=(QUEUE){x-1,y};
if (x<n && flag[x+1][y]!=tag && a[x+1][y]==num) flag[x+1][y]=tag,Q[tail++]=(QUEUE){x+1,y};
if (y>1 && flag[x][y-1]!=tag && a[x][y-1]==num) flag[x][y-1]=tag,Q[tail++]=(QUEUE){x,y-1};
if (y<m && flag[x][y+1]!=tag && a[x][y+1]==num) flag[x][y+1]=tag,Q[tail++]=(QUEUE){x,y+1};
}
}
void change(int xstart,int ystart,int num,int now){
int head=0,tail=1;
Q[0]=(QUEUE){xstart,ystart};
flag[xstart][ystart]=tag;
while (head<tail){
int x=Q[head].x,y=Q[head++].y;
a[x][y]=now;
if (x>1 && flag[x-1][y]!=tag && a[x-1][y]==num) flag[x-1][y]=tag,Q[tail++]=(QUEUE){x-1,y};
if (x<n && flag[x+1][y]!=tag && a[x+1][y]==num) flag[x+1][y]=tag,Q[tail++]=(QUEUE){x+1,y};
if (y>1 && flag[x][y-1]!=tag && a[x][y-1]==num) flag[x][y-1]=tag,Q[tail++]=(QUEUE){x,y-1};
if (y<m && flag[x][y+1]!=tag && a[x][y+1]==num) flag[x][y+1]=tag,Q[tail++]=(QUEUE){x,y+1};
}
}
void solve(){
while (!Heap.empty()){
node u=Heap.top();Heap.pop();
if (vis[u.x][u.y] || a[u.x][u.y]-b[u.x][u.y]) continue;
ans=inf,tag++;
BFS(u.x,u.y,u.high,0);
if (!ans) tag++,BFS(u.x,u.y,u.high,1);
if (ans<=u.high) continue;
tag++,change(u.x,u.y,u.high,ans);
}
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
scanf("%d",&a[i][j]),b[i][j]=a[i][j],
Heap.push((node){a[i][j],i,j});
solve();
int answer=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++) answer+=max(a[i][j]-b[i][j],0);
printf("%d\n",answer);
return 0;
}