东方14模拟赛之岛屿
02:岛屿
- 总时间限制:
- 40000ms
- 单个测试点时间限制:
- 4000ms
- 内存限制:
- 128000kB
- 描述
-
从前有一座岛屿,这座岛屿是一个长方形,被划为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天的连通块个数。
- 样例输入
-
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 - 这题比较尴尬,因为数组开小了给我爆re,导致考试结束前20分钟一直卡到88.。。。。最后读了一遍题才发现
- 并查集
- 读入数据
- 把矩阵转化为一条链
- 把链按照高度排序 (降序
- 我们倒着枚举高度值
- (此处有优化吗,要是当前高度无法达到,那么记录此时i值为tmp,下次从tmp开始枚举岛屿
- 记录vis表示,当前岛屿可已经可以永远漏出水面,
- 如果枚举到高度高于水面并且没有被记录的,此时计数器++
- 并且查看他上下左右是否有被访问的点
- 要是有的话查看他的祖先是否与该点祖先相同,不同则cnt--并且合并
- 说明此时可以作为连通块一部分
-
#include<cstdio> #include<algorithm> using namespace std; const int maxn = 3002; int map[maxn][maxn],id[maxn][maxn]; bool vis[maxn*maxn];int father[maxn*maxn]; #define LL long long int c; int n,m,q; struct node{ int x,y,high,id; }miku[maxn*maxn]; bool cmp(node a,node b) { return a.high>b.high; } LL ccnt=0,ans[maxn*1000];int t[maxn*1000],cnt=0; int fs[5]={1,0,-1,0,1}; inline int find(int x) { if(father[x]!=x) father[x]=find(father[x]); return father[x]; } int pd(int x,int y) { vis[id[x][y]]=1; int tmp=0; for(int i=0;i<4;i++) { int xx=x+fs[i]; int yy=y+fs[i+1]; if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&vis[id[xx][yy]]) { int f1=find(id[x][y]),f2=find(id[xx][yy]); if(f1!=f2) { father[f2]=f1; tmp++; } } } return tmp; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&map[i][j]),miku[++cnt].high=map[i][j],miku[cnt].x=i,father[cnt]=cnt, miku[cnt].y=j; sort(miku+1,miku+cnt+1,cmp); for(int i=1;i<=cnt;i++) { id[miku[i].x][miku[i].y]=i; } scanf("%d",&q); for(int i=1;i<=q;i++) scanf("%d",&t[i]); int tmp=1; for(int k=q;k>=1;k--) { for(int i=tmp;i<=cnt;i++) { if(miku[i].high>t[k]) { if(!vis[i]) { ccnt++; ccnt-=pd(miku[i].x,miku[i].y); } } else { tmp=i; break; } } ans[k]=ccnt; } for(int i=1;i<=q;i++) printf("%lld ",ans[i]); return 0; }