LGP5423题解
这种思路的题都做过 114514 遍了怎么还是记不住呢(
考虑枚举连通块的最大值。
那么考虑将权值从小到大排序,每次加入一个位置后只需要判断所在连通块是否存在洞即可。
通过平面图欧拉公式 \(F+V=E+2\) 即可判断。
这几个东西显然可以直接维护,复杂度 \(O(n^2\alpha(n))\)。
#include<algorithm>
#include<cstdio>
#include<cctype>
const int M=755,SZ=750*750+5;
int n,cnt,id[M][M],h[M][M];bool vis[M][M];
int f[SZ],sz[SZ],sum[SZ];
struct pr{
int x,y,w;
pr(const int&x=0,const int&y=0,const int&w=0):x(x),y(y),w(w){}
inline bool operator<(const pr&it)const{
return w<it.w;
}
inline bool operator==(const pr&it)const{
return x==it.x&&y==it.y&&w==it.w;
}
}v[M*M];
inline int Find(const int&u){
return f[u]==u?u:f[u]=Find(f[u]);
}
inline int Merge(const int&u,const int&v){
return u^v&&(f[u]=v,sz[v]+=sz[u],sum[v]+=sum[u]),v;
}
inline int read(){
int n(0);char s;while(!isdigit(s=getchar()));while(n=n*10+(s&15),isdigit(s=getchar()));return n;
}
signed main(){
long long ans(0);n=read();
for(int i=0;i<=n+1;++i)h[i][0]=h[0][i]=h[i][n+1]=h[n+1][i]=1e9;
for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)v[id[i][j]=++cnt]=pr(i,j,h[i][j]=read());
std::sort(v+1,v+cnt+1);for(int i=1;i<=cnt;++i)f[i]=i,sz[i]=sum[i]=1;
for(int i=1;i<=cnt;++i){
const int&x=v[i].x,&y=v[i].y;vis[x][y]=true;
if(h[x][y]>h[x][y-1])--sz[Merge(Find(id[x][y]),Find(id[x][y-1]))];
if(h[x][y]>h[x-1][y])--sz[Merge(Find(id[x][y]),Find(id[x-1][y]))];
if(h[x][y]>h[x][y+1])--sz[Merge(Find(id[x][y]),Find(id[x][y+1]))];
if(h[x][y]>h[x+1][y])--sz[Merge(Find(id[x][y]),Find(id[x+1][y]))];
const int&id=Find(::id[x][y]);
if(vis[x][y]&&vis[x][y-1]&&vis[x-1][y]&&vis[x-1][y-1])++sz[id];
if(vis[x][y]&&vis[x][y-1]&&vis[x+1][y]&&vis[x+1][y-1])++sz[id];
if(vis[x][y]&&vis[x][y+1]&&vis[x-1][y]&&vis[x-1][y+1])++sz[id];
if(vis[x][y]&&vis[x][y+1]&&vis[x+1][y]&&vis[x+1][y+1])++sz[id];
if(sz[id]==1)ans+=sum[id];
}
printf("%lld",ans);
}