【JZOJ】【并查集】设备塔

LinkLink

JZOJJZOJ 38093809

DescriptionDescription

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

InputInput

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

OutputOutput

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

SampleSample InputInput

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

SampleSample OutputOutput

6

HintHint

• 对于分值为30 的子任务1,保证N;M <=100;K<= 5000
• 对于分值为30 的子任务2,保证N;M <=3000;K <= 5000
• 对于分值为40 的子任务3,保证N;M <=3000;K <= 300000。


黄色点表示可加的点,红色点表示不可加的点

TrainTrain ofof ThoughtThought

因为是圆柱体,把原图倍长一倍,每次加一个点,就在它这个图的复制图的对应点也标记上,判断这两个点是否联通,联通则不可加,否则就可以加
判断是否联通可以用并查集
但是!
∵ 如果你当前在(x,(x, 1)1),然后往左跳, 变为(x,(x, 0)0),而(x,(x, 0)0)其实等于(x,(x, 2m)2 * m)
∴ 需要这一类操作:
在这里插入图片描述

CodeCode

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;

int n, m, x, y, tot, t, ans;
int a[3005][6005], fa[2000005];
int dx[8] = {0, 1, 1, 1, 0, -1, -1, -1};
int dy[8] = {1, 1, 0, -1, -1, -1, 0, 1}; 

int find(int x)
{
	if (fa[x] == x) return x;
	 else return fa[x] = find(fa[x]);
}//寻找祖先

bool check(int x, int y)
{
	int x2 = x, y2 = y + m;
	for (int i = 0; i < 8; ++i)
	{
		int xa = x + dx[i], ya = y + dy[i];
		if (ya < 1) ya = 2 * m;
		if (ya > 2 * m) ya = 1;
		if (xa < 1 || xa > n || !a[xa][ya]) continue;
		for (int j = 0; j < 8; ++j)
		{
			int xb = x2 + dx[j], yb = y2 + dy[j];
			if (yb > 2 * m) yb = 1;
			if (yb < 1) yb = 2 * m;
			if (xb < 1 || xb > n || !a[xb][yb]) continue;
			if (a[xa][ya] && a[xb][yb] && find(a[xa][ya]) == find(a[xb][yb])) //判断是否联通
			 return 0; 
		
		}
	}
	return 1;
}

void unicom(int ax, int bx)
{
	int Fa = find(ax), Fb = find(bx);
	if (Fa == Fb) return;
	if (Fa > Fb) fa[Fa] = Fb;
	 else fa[Fb] = Fa;
}//联通祖先

void findfa(int tx, int ty)
{
	a[tx][ty] = ++tot;
	fa[tot] = tot;
	for (int i = 0; i < 8; ++i)
	{
		int txa = tx + dx[i], tya = ty + dy[i];
		if (tya < 1) tya = 2 * m;
		if (tya > 2 * m) tya = 1;
		if (txa < 1 || txa > n || !a[txa][tya]) continue;
	    unicom(tot, a[txa][tya]);
	}
}

int main()
{
	scanf("%d%d%d", &n, &m, &t);
	for (int i = 1; i <= t; ++i)
	{
		scanf("%d%d", &x, &y);
		if (check(x, y)) {//是否联通
			ans++;
			findfa(x, y); findfa(x, y + m);//刷新它邻点的祖先(并且帮当前点找到祖先)
		}
	}
	printf("%d", ans);
}
发布了224 篇原创文章 · 获赞 35 · 访问量 1万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章