NCPC 2016 A-Artwork (离线+并查集+二维数组压缩)

14 篇文章 0 订阅
1 篇文章 0 订阅

NCPC 2016 A-Artwork (离线+并查集+二维数组压缩

NCPC 2016 A-Artwork (离线+并查集+二维数组压缩)

题目

https://codeforces.com/gym/101550/attachments
在这里插入图片描述

题意

给你n,m,q三个数,代表一张n*m的图,接下来有q次询问。
q次询问给你四个数x1,y1,x2,y2 (x1=x2 or y1=y2)。表示在方格中涂黑一块区域。
然后问每一次涂黑一块区域之后,图中的联通块还有多少。

题解

首先排除dfs!太暴力了,然后这题我们可以使用并查集,把每个小方格元素都当成一个集合,然后去merge它们,最后剩下的联通块就是答案。但是每一次询问都重新刷新计算集合,这样时间复杂度会更高,所以我们可以采用离线的方式。就是从最后一步往前推。
因为二维的的图,我不会并查集,所以就把它压缩成一维了。

AC代码

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
#define ll long long
const int maxn = 1e6+5;
const int maxm = 1e4+5;
int vis[maxn],pre[maxn];
int x1[maxm],x2[maxm],y1[maxm],y2[maxm];
int n,m,q;
int sum;
int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int ans[maxm];
int Hash(int y,int x)
{
	return x*n+y;
}
int find(int x)
{
	if(x == pre[x]) return x;
	return pre[x] = find(pre[x]);
}
void merge(int x, int y)
{
	int fx = find(x), fy = find(y);
	if (fx != fy)
	{
		pre[fx] = fy;
		sum--;
	}
}
void dfs(int x,int y)
{
	int tx,ty;
	for(int i=0;i<4;i++)
	{
		tx = x+dir[i][0];
		ty = y+dir[i][1];
		if(tx>=0&&ty>=0&&tx<n&&ty<m)
		{
			if(vis[Hash(tx,ty)]==0)
			{
				merge(Hash(tx,ty),Hash(x,y));
			}
		}
	}
}
int main()
{
	scanf("%d %d %d",&n,&m,&q);
	sum = n*m;
	for(int k=0;k<q;k++)
	{
		scanf("%d %d %d %d",&x1[k],&y1[k],&x2[k],&y2[k]);
		for(int i=x1[k]-1;i<x2[k];i++)
			for(int j=y1[k]-1;j<y2[k];j++)
			{
				if(vis[Hash(i,j)]==0)
				{
					sum--;
				}
				vis[Hash(i,j)]++;
//				printf("hash(%d,%d) = %d\n",i,j,hash(i,j));
			}
	}
	for(int i=0;i<n*m;i++)	pre[i] = i;
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
			if(vis[Hash(i,j)]==0)
			{
				dfs(i,j);
			}
	for(int k=q-1;k>=0;k--)
	{
		ans[k] = sum;
		for(int i=x1[k]-1;i<x2[k];i++)
			for(int j=y1[k]-1;j<y2[k];j++)
			{
				vis[Hash(i,j)]--;
				if(vis[Hash(i,j)]==0)
				{
					sum++;
					dfs(i,j);
				}
			}
	}
	for(int i=0;i<q;i++)
		printf("%d\n",ans[i]);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值