【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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章