1. 程式人生 > 其它 >CF1166F - Vicky's Delivery Service(並查集,啟發式合併)

CF1166F - Vicky's Delivery Service(並查集,啟發式合併)

給出節點數為\(n\),邊數為\(m\)的圖。

保證每個點對都是互連的。

定義彩虹路:這條路經過\(k\)個節點,對於\(x(x\%2=0)\)的節點,左右兩條邊顏色相同。

現在有\(q\)次操作。

第一種操作是新增一條邊。

第二種操作是回答是否能經過彩虹邊從\(a\)節點到達\(b\)節點。

做法:

能相互到達的點用並查集連起來。

具體做法就是:

\(a-b-c\)的邊的顏色相同時,我們把\(a\)\(c\)節點用合併,代表\(a\)\(c\)互連。

對於節點\(a\),每個顏色的邊只需要儲存一條,這樣可以快速合併節點。

這裡可以列舉b的邊集,按序合併即可。

但是還有一種情況,\(x\)

節點和\(y\)節點經過的邊數為奇數,這樣最後一條邊的顏色就不重要了。

所以如果兩個節點不在一個集合內,就需要看其中一個點能否通過另一個集合到達。

對每個集合維護一個set,然後列舉每條邊,把這條邊兩端的節點塞進另一個節點的集合的set。

加邊的時候,對邊兩邊的節點維護並查集。

合併集合的時候,對集合對應的set,啟發式合併即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m,c,q;
map<int,int> g[maxn];
set<int> st[maxn];
int father[maxn];
int findfather (int x) {
	int a=x;
	while (x!=father[x]) x=father[x];
	while (a!=father[a]) {
		int z=a;
		a=father[a];
		father[z]=x;
	} 
	return x;
} 
void un (int x,int y) {
	x=findfather(x);
	y=findfather(y);
	if (x==y) return;
	if (st[x].size()<st[y].size()) {
		father[x]=y;
		for (auto it:st[x]) st[y].insert(it);
	}
	else {
		father[y]=x;
		for (auto it:st[y]) st[x].insert(it);
	}
}
int main () {
	scanf("%d%d%d%d",&n,&m,&c,&q);
	for (int i=1;i<=n;i++) father[i]=i;
	while (m--) {
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		st[findfather(y)].insert(x);
		st[findfather(x)].insert(y);
		if (g[x].count(z)) {
			un(g[x][z],y);
		}
		else {
			g[x][z]=y;
		}
		if (g[y].count(z)) {
			un(g[y][z],x);
		}
		else {
			g[y][z]=x;
		}
	}
	while (q--) {
		char op;
		getchar();
		scanf("%c",&op);
		if (op=='+') {
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			st[findfather(y)].insert(x);
			st[findfather(x)].insert(y);
			if (g[x].count(z)) {
				un(g[x][z],y);
			}
			else {
				g[x][z]=y;
			}
			if (g[y].count(z)) {
				un(g[y][z],x);
			}
			else {
				g[y][z]=x;
			}
		}
		else {
			int x,y;
			scanf("%d%d",&x,&y);
			if (findfather(x)==findfather(y)) {
				printf("Yes\n");
			}
			else if (st[findfather(x)].count(y)) {
				printf("Yes\n");
			}
//			else if (st[findfather(y)].count(x)) {
//				printf("Yes\n");
//			}
			else {
				printf("No\n");
			}
		}
	}
}