ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1166F - Vicky's Delivery Service(并查集,启发式合并)

2021-11-08 15:34:12  阅读:151  来源: 互联网

标签:set Service int 查集 father Delivery maxn 集合 节点


给出节点数为\(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");
			}
		}
	}
}

标签:set,Service,int,查集,father,Delivery,maxn,集合,节点
来源: https://www.cnblogs.com/zhanglichen/p/15524433.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有