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);
}
posted @ 2022-09-09 14:57  Prean  阅读(15)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};