问题 B: water
时间限制: 1 Sec 内存限制: 256 MB
题目描述
有一块矩形土地被划分成 n*m 个正方形小块。这些小块高低不平,每一小块都有自己的高度。水流可以由任意一块地流向周围四个方向的四块地中,但是不能直接流入对角相连的小块中。
一场大雨后,由于地势高低不同,许多地方都积存了不少降水。给定每个小块的高度,求每个小块的积水高度。
注意:假设矩形地外围无限大且高度为0。
输入
第一行包含两个非负整数n,m。
接下来n 行每行m 个整数表示第i 行第j 列的小块的高度。
输出
输出n 行,每行m 个由空格隔开的非负整数,表示每个小块的积水高度。
样例输入
3 3
4 4 0
2 1 3
3 3 -1
样例输出
0 0 0
0 1 0
0 0 1
提示
对于20%的数据 n,m<=4
对于40%的数据 n,m<=15
对于60%的数据 n,m<=50
对于100%的数据 n,m<=300,|小块高度|<=10^9。
在每一部分数据中,均有一半数据保证小块高度非负
其实我们要求的是某个点到边界的路径中最大高度的最小值。因为一条路径能盛水的最大高度就是这条路径的上的最大高度,最终某个点能盛水的高度是所有路径上最高高度的最小值。所以可以跑spfa,求出这个,就能算出盛水的高度了。
#pragma GCC optimize("O3")
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define N 300005
#define inf 1000000000
#define ll long long
using namespace std;
int read()
{
int sum=0,f=1;char x=getchar();
while(x<'0'||x>'9'){if(x=='-')f=-1;x=getchar();}
while(x>='0'&&x<='9'){sum=(sum<<1)+(sum<<3)+x-'0';x=getchar();}
return sum*f;
}
struct node
{
int x,y;
node(){}
node(int x_,int y_){x=x_,y=y_;}
};
int n,m;int vis[304][304];
ll a[304][304],dis[305][305];
int wz[4][2]={0,1,0,-1,1,0,-1,0};
queue<node> q;
void spfa()
{
while(!q.empty())
{
node x=q.front();q.pop();vis[x.x][x.y]=0;
for(int i=0;i<4;i++)
{
node to;to.x=x.x+wz[i][0],to.y=x.y+wz[i][1];
if(to.x<=1||to.x>=n||to.y>=m||to.y<=1)continue;
int k=max(a[to.x][to.y],dis[x.x][x.y]);
if(dis[to.x][to.y]>k)
{
dis[to.x][to.y]=k;
if(!vis[to.x][to.y]){vis[to.x][to.y]=1;q.push(to);}
}
}
}
}
int main()
{
memset(dis,120,sizeof(dis));
n=read();m=read();
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)a[i][j]=read();
for(int i=1;i<=n;i++)
{
dis[i][1]=max(0ll,a[i][1]);
dis[i][m]=max(0ll,a[i][m]);
q.push(node(i,1));q.push(node(i,m));
vis[i][1]=vis[i][m]=1;
}
for(int i=1;i<=m;i++)
{
dis[1][i]=max(0ll,a[1][i]);
dis[n][i]=max(0ll,a[n][i]);
q.push(node(1,i));q.push(node(n,i));
vis[1][i]=vis[n][i]=1;
}
spfa();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
int k=max(0ll,dis[i][j]-a[i][j]);
printf("%d ",k);
}
printf("\n");
}
}