T2 water
官方题解:
一个块的水平面高度就是从这个块走出矩形的所有路径上的最 大值的最小值。 相邻块连边,权值为两块的较大值,矩形 边界的块向“矩形外”连边,权值为 max(高度,0)。 做最小生成树。 时间复杂度 O(nmlognm)。
瓶颈生成树:满足最大的边最小。
最小生成树:也就是最小瓶颈树。
我来说说:
1.为什么能用最小生成树??
正如题解,一个格子的水是由它流向外围的所有路径中,每条路径上的最大值 的最小值。(木桶原理)
可以用bfs解决。
最小生成树可以求出最小的路径,再在该路径上取最大值即为最大蓄水量。
2.一开始想的是对每一个格子kruscal,但发现可以一次解决所有答案。
3.对每一个点,寻找该点所在联通块时,O(N)遍历会TLE(70),用vector解决。
好题,难想。

1 #include<bits/stdc++.h>
2 using namespace std;
3 const int maxn=310;
4 const int N=maxn*maxn*4;
5 const int mod=1e9+7;
6 int dx[]={0,1,-1,0,0};
7 int dy[]={0,0,0,1,-1};
8 int n,m;
9 int zb(int i,int j){return (i-1)*m+j;}
10 int mp[maxn][maxn],cnt[maxn][maxn];
11 struct Edge{
12 int w,f,to,nxt;
13 bool operator < (const Edge &b) const {
14 return w<b.w;
15 }
16 }ed[N];
17 int head[N],ecnt;
18 void addedge(int f,int to,int w){
19 ed[++ecnt].w=w;
20 ed[ecnt].f=f;
21 ed[ecnt].to=to;
22 ed[ecnt].nxt=head[f];
23 head[f]=ecnt;
24 }
25 int fa[N],ans[N];
26 int find(int x){
27 if(fa[x]==x) return x;
28 return fa[x]=find(fa[x]);
29 }
30 vector <int> v[N];
31 void deal_(){
32 for(int i=0;i<=n*m;i++) fa[i]=i,v[i].push_back(i);
33 int target=0;
34 for(int i=1;i<=ecnt;i++){
35 int a=ed[i].f,b=ed[i].to;
36 int ffa=find(a),ffb=find(b);
37 if(ffa!=ffb){
38 if(ffb==target&&ffa!=target) swap(ffa,ffb),swap(a,b);
39 if(ffa==target){
40 for(int j=0;j<v[ffb].size();j++){
41 ans[v[ffb][j]]=ed[i].w;
42 }
43 }
44 fa[ffb]=ffa;
45 for(int j=0;j<v[ffb].size();j++){
46 v[ffa].push_back(v[ffb][j]);
47 }
48 }
49 }
50 }
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",&mp[i][j]);
56 for(int i=1;i<=n;i++)
57 for(int j=1;j<=m;j++){
58 for(int d=1;d<=4;d++){
59 if(i+dx[d]<=0||i+dx[d]>n||j+dy[d]<=0||j+dy[d]>m){
60 addedge(0,zb(i,j),max(mp[i][j],0));
61 // addedge(zb(i,j),0,max(mp[i][j],0));
62 continue;
63 }
64 addedge(zb(i,j),zb(i+dx[d],j+dy[d]),max(mp[i][j],mp[i+dx[d]][j+dy[d]]));
65 // addedge(zb(i+dx[d],j+dy[d]),zb(i,j),max(mp[i][j],mp[i+dx[d]][j+dy[d]]));
66 }
67 }
68 sort(ed+1,ed+1+ecnt);
69 memset(ans,-1,sizeof ans);
70 deal_();
71 for(int i=1;i<=n;i++){
72 for(int j=1;j<=m;j++){
73 printf("%d ",ans[zb(i,j)]-mp[i][j]);
74 }
75 puts("");
76 }
77 return 0;
78
79 }
