【模拟赛·岛屿】
【问题描述】
从前有一座岛屿,这座岛屿是一个长方形,被划为 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
.