【模拟赛·岛屿】

【问题描述】

从前有一座岛屿,这座岛屿是一个长方形,被划为 N*M 的方格区域,每个区域都有一个确定的高度。不幸的是海平面开始上涨,在第 i 年,海平面的高度为 t[i]。如果一个区域的高度小于等于海平面高度,则视为被淹没。那些没有被淹没的连通的区域够成一个连通块。现在问第 i 年,这样的连通块有多少个。例如:第一年海平面高度为 1,有 2 个连通块。第二年海平面高度为 2,有 3 个连通块。

【输入】

第一行包含两个数 N,M。接下来是一个 N*M 的矩阵,第 i 行第 j 列表示这个格子的高度 h[i][j] 接下来是一个数 T,表示有 T 天,最后一行有 T 个数,第 i 个数表示第 i 天的水位高度。(保证是递增的)

【输出】

输出包含一行 T 个数,第 i 个数表示第 i 天的连通块个数。

【输入输出样例】

island.in

island.out

4 5 1 2 3 3 1 1 3 2 2 1 2 1 3 4 3 1 2 2 2 2 5 1 2 3 4 5 2 3 1 0 0

【数据范围】

对于 50%的数据:1 <= n*m <= 1000, 1<= T <=3000

对于 100%的数据:1<= n <= 3000 , 1<= m <= 3000 , 1<=T<=100000 1<= h[i][j] <=10^9

【题解】

      ①正难则反。

      ②加入当前高于水位的块,使用并查集维护连通块去重即可。

      ③试试FREAD读入优化吧。

#include<stdio.h>
#include<algorithm>
#define OUT(i,j) (i<1||i>n||j<1||j>m)
#define go(i,a,b) for(int i=a;i<=b;i++)
#define ro(i,a,b) for(int i=a;i>=b;i--)
const int N=3005;bool dry[N*N];
struct info{int x,y,h;}a[N*N];
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
int n,m,s,H,fa[N*N],T,t[N*N],ans[N*N],now; 
int ID(int x,int y){return (x-1)*m+y;}
bool cmp(info A,info B){return A.h<B.h;}
int Find(int u){return u==fa[u]?u:fa[u]=Find(fa[u]);}

char Getchar()
{
	static char C[1000000],*p1,*p2;
	if(p1==p2)p2=(p1=C)+fread(C,1,1000000,stdin);
	if(p1==p2)return EOF;return *p1++;
}

void read(int &x)
{
	x=0;char c=Getchar();
	while(c<'0'||c>'9')c=Getchar();
	while(c>='0'&&c<='9')x=x*10+c-'0',c=Getchar();
}

int main()
{
	freopen("island.in","r",stdin);
	freopen("island.out","w",stdout);
	
	read(n);read(m);
	go(i,1,n)go(j,1,m)read(H),a[++s]=(info){i,j,H},fa[s]=s;
	read(T);go(i,1,T)read(t[i]);std::sort(a+1,a+s+1,cmp);
	ro(i,T,1){while(s&&a[s].h>t[i])
	{
		now++;dry[ID(a[s].x,a[s].y)]=1;go(k,0,3)
		{
			if(OUT(a[s].x+dx[k],a[s].y+dy[k]))continue;
			int u=ID(a[s].x,a[s].y),v=ID(a[s].x+dx[k],a[s].y+dy[k]);
			if(!dry[v])continue;int U=Find(u),V=Find(v);
			if(U==V)continue;fa[V]=U;now--;
		}s--;
	}
	ans[i]=now;}go(i,1,T)printf("%d ",ans[i]);return 0;
}//Paul_Guderian

.

原文地址:https://www.cnblogs.com/Damitu/p/7793302.html