• 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");
    			}
    		}
    	}
    }
    
  • 相关阅读:
    需求层次性、需求分类
    CSMA/CA协议详解
    Git笔记:GitFlow工作流模拟、分支管理、使用规范
    Vue.js笔记(四) 路由router与重定向
    DolphinScheduler 源码分析之 DAG类
    linux 一分钟安装maven linux
    linux 一分钟搭建zookeeper linux 单机版(亲测可用)
    canal-adapter1.1.14最新版本安装的过程中出现的NullPointerException异常
    yum.repos.d中的变量($releasever与$basearch)
    索引知识
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/15524433.html
Copyright © 2020-2023  润新知