A.Islands
这种联通块的问题一看就知道是并查集的思想。
做法:从高水位到低水位依序进行操作,这样每次都有新的块浮出水面,可以在前面的基础上进行合并集合的操作。
给每个位置分配一个数字,方便合并集合。同时将这些数字也排一个序,降低枚举的复杂度。合并集合时向四周查询浮出水面但是没有合并到同一集合的点进行合并。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define N 1007 struct node { int x,y,h; }p[N*N]; int a[N*N],sh[100005],cnt[100005],fa[N*N]; int n,m; int dx[4] = {0,0,1,-1}; int dy[4] = {1,-1,0,0}; int cmp(node ka,node kb) { return ka.h < kb.h; } int findset(int x) { if(x != fa[x]) fa[x] = findset(fa[x]); return fa[x]; } inline int ok(int x,int y) { if(x < n && x >= 0 && y < m && y >= 0) return 1; return 0; } int main() { int t,i,j,k,q,ind,pos; scanf("%d",&t); while(t--) { memset(cnt,0,sizeof(cnt)); scanf("%d%d",&n,&m); for(i=0;i<n;i++) { for(j=0;j<m;j++) { pos = i*m+j; fa[pos] = pos; scanf("%d",&a[pos]); p[pos].x = i,p[pos].y = j,p[pos].h = a[pos]; } } scanf("%d",&q); for(i=0;i<q;i++) scanf("%d",&sh[i]); sort(p,p+n*m,cmp); i = n*m-1; for(j=q-1;j>=0;j--) { cnt[j] = cnt[j+1]; while(sh[j] < p[i].h) //浮出水面 { cnt[j]++; ind = p[i].x*m+p[i].y; int fx = findset(ind); for(k=0;k<4;k++) { int tx = p[i].x + dx[k]; int ty = p[i].y + dy[k]; if(!ok(tx,ty)) continue; int newind = tx*m+ty; int fy = findset(newind); if(fx != fy && sh[j] < a[newind]) //浮出水面且没有合并 { fa[fy] = fx; //不能使fa[fx] = fy.因为本次fx不会再findset. cnt[j]--; } } i--; } } for(i=0;i<q;i++) printf("%d ",cnt[i]); printf("\n"); } return 0; }