【JZOJ】【并查集】设备塔

D e s c r i p t i o n Description Description

为了封印辉之环,古代塞姆利亚大陆的人民在异空间中建造了一座设备塔。
简单的说,这座设备塔是一个漂浮在异空间中的圆柱体,圆柱体两头的圆是计算核心,而侧面则是
传输信息所用的数据通道,划分成N *m 个区块。
然而,随着工作的继续进行,他们希望把侧面的一部分区块也改造成其他模块。然而,任何时候都
必须保证存在一条数据通道,能从圆柱体的一端通向另一端。
由于无法使用辉之环掌控下的计算系统,他们寻求你的帮助来解决这个问题。他们将逐个输入想要
改造的区域,而你则执行所有可行的改造并忽略可能导致数据中断的改造。

I n p u t Input Input

第一行,包含两个整数N;M;K,表示侧面的长和宽,以及操作数。
接下来K 行,每行包含三个整数xi; yi,表示操作的区块的坐标。(0<=y=<M)
数据保证不会对已经操作成功的区块进行操作。

O u t p u t Output Output

输出一行,表示有多少个操作可以被执行。

S a m p l e I n p u t SampleInput SampleInput

3 4 9
2 2
3 2
2 3
3 4
3 1
1 3
2 1
1 1
1 4

S a m p l e O u t p u t SampleOutput SampleOutput

6

思路

判断从上到下是否有路径
其实就是判断放的方块是否能够连成一块
就等于将 n ∗ m n*m nm的图复制一遍
每一次放就等于放两个方块
然后让方块时判断两个方块附近的方块是否连通
(这里用到并查集)

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int dx[9] = {0, 1, 1, 1, 0, -1, -1, -1, 0};
const int dy[9] = {0, 1, 0, -1, -1, -1, 0, 1 ,1};
int Fa[600015], M[3005][6015];
int Ans, n, m, t, x, y, sx, sy;
int Read()//快读,然后并没有什么卵用
{
	int l = 0, r = 1; char k = getchar();
	while(!(k >= '0' && k <= '9') && k != '-')break;
	if(k < '0' || k > '9')r = -1, k = getchar();
	while(k >= '0' && k <= '9')l = l * 10 + k - '0', k = getchar();
	return l * r;
}
bool Check(int x, int &y)//判断是否超界,并且将越界的y弄到另一边(因为他是圆柱)
{
	if(x < 1 || x > n)return 0;
	if(y < 1)y = 2 * m;
	if(y > 2 * m)y = 1;
	if(!M[x][y])return 0;
	return 1;
}
int find(int k)//并查集
{
	if(Fa[k] == k)return k;
	return Fa[k] = find(Fa[k]);
}
bool init(int xx, int xy)
{
	int yx = xx, yy = xy + m;//复制出来的方块位置
	for(int i = 1; i <= 8; ++i)//第一个四周的方块
		{
			int lx = xx + dx[i];
			int ly = xy + dy[i];
			if(!Check(lx, ly))continue;
			for(int j = 1; j <= 8; ++j)//第一个四周的方块(因为同一个方向可能并不连通,所以要两个for)
			{
				int rx = yx + dx[j];
				int ry = yy + dy[j];
				if(!Check(rx, ry))continue;
				if(find(M[lx][ly]) == find(M[rx][ry])
				&& M[lx][ly] && M[rx][ry])return 0;//判断是否连通
			}
		}
	return 1;
}
void bol(int x, int y)
{
	int la = find(x);
	int lb = find(y);
	if(la < lb)Fa[lb] = la;
	else if(la > lb)Fa[la] = lb;//归为同一个祖先
	return;
	
}
void build(int x,int y)
{
	M[x][y] = ++Ans;
	Fa[Ans] = Ans;
	for(int i = 1; i <= 8; i++)//找祖先
	{
		int l = x + dx[i];
		int r = y + dy[i];
		if(!Check(l, r))continue;
		bol(M[x][y],M[l][r]);
	}
	return;
}
int main()
{
	scanf("%d%d%d", &n, &m, &t);
	for(int l = 1; l <= t; l++)
	{
		scanf("%d%d", &x, &y);
		if(init(x, y))
		{
			build(x, y);
			build(x, y + m);
		}
	}
	printf("%d", Ans / 2);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值