树状数组--water
对于这道题,首先要明确,块的积水量取决于什么
1、如果水一直只往一个方向流,块的积水量,等于从它出发,沿该方向的最大高度,因为之前不管有过低,到了最大高度都会被卡住;
2、如果水往两个方向一直流,块的积水量,由1知,每条路径的最大积水量分别为max1,max2,如果两条路径一起考虑呢?应该为min(max1,max2)(取决于木桶原理);
3、由1,2推出,块的积水量等于从块出发,走到边界的x条路径的高度最大值得最小值;
知道了块的积水量是什么,我们再考虑如何求解
我们希望求出一条通往边界路径的最大值,且这个最大值是所有路径中最小的,我们贪心的想,如果加的每一条边都尽可能的小,当形成一条通往边界的路径时,当前路径的最大值一定是最小的,这个思想就很像一个算法,没错就是最小生成树;
*整体思路:
相邻矩形连边,边权为高度较大值(因为求一条路径的最大值,较小值没有贡献),最小生成树,使所有的节点最后都直接或间接的与边界相连(不一定是同一个边界),最后每次从边界开始dfs;(这可能是我写的最长最详细的一篇题解了吧,我不会画图,画图看的话应该会更直观)
代码:
1 #include <iostream>
2 #include <algorithm>
3 #include <cstdio>
4 #include <cstring>
5 using namespace std;
6 const int maxn=1e5;
7 int head[2*maxn],tot,n,m,h[maxn*2],fa[maxn],ans[2*maxn],cnt;
8 inline int getnum(int x,int y){
9 if (x>n||y>m||!x||!y) return 0;
10 return (x-1)*m+y;
11 }
12 struct node{
13 int u,v,w;
14 }water[2*maxn];
15 struct e{
16 int to,next,w;
17 }ed[2*maxn];
18 bool cmp(node x,node y){
19 return x.w<y.w;
20 }
21 inline int find(int x){
22 if(fa[x]==x) return x;
23 else return find(fa[x]);
24 }
25 inline void update(int x,int y){
26 int fx=find(x),fy=find(y);
27 fa[fx]=fy;return;
28 }
29 inline void add(int u,int v,int w){
30 ed[++cnt].to=v;
31 ed[cnt].w=w;
32 ed[cnt].next=head[u];
33 head[u]=cnt;
34 }
35 inline void mintree(){
36 for (int i = 0;i <= n*m;i++) fa[i]=i;
37 sort(water+1,water+1+tot,cmp);
38 for (int i = 1;i <= tot;i++){
39 int u=water[i].u,v=water[i].v,w=water[i].w;
40 if (find(u)!=find(v)) update(u,v),add(u,v,w),add(v,u,w);
41 }
42 }
43 inline void dfs(int nowid,int fa){
44 for (int i = head[nowid];i;i=ed[i].next){
45 int to=ed[i].to,w=ed[i].w;
46 if(to!=fa) ans[to]=max(ans[nowid],w),dfs(to,nowid);
47 }
48 }
49 int dirx[5]={0,-1,0,1,0};
50 int diry[5]={0,0,1,0,-1};
51 int main(){
52 scanf ("%d%d",&n,&m);
53 for (int i = 1;i <= n;i++)
54 for (int j = 1;j <= m;j++)
55 scanf ("%d",&h[getnum(i,j)]);
56 for (int i = 1;i <= n;i++){
57 for (int j = 1;j <= m;j++){
58 int u=getnum(i,j);
59 for (int k = 1;k <= 4;k++){
60 int v=getnum(i+dirx[k],j+diry[k]);
61 water[++tot]={u,v,max(h[u],h[v])};
62 }
63 }
64 }
65 mintree();
66 dfs(0,0);
67 for (int i = 1;i <= n*m;i++){
68 printf ("%d ",ans[i]-h[i]);
69 if (i%m==0) cout<<endl;
70 }
71 return 0;
72 }