东方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;
}

 

posted @ 2017-07-19 21:47  zzzzx  阅读(232)  评论(0编辑  收藏  举报