【ybt金牌导航6-2-3】连通性询问(并查集)(启发式合并)

连通性询问

题目链接:ybt金牌导航6-2-3

题目大意

给你 n 个点,一开始没有边。
然后有两种操作,加一条双向边,以及询问两个点之间最早在加入多少边的时候就连通了。
如果没有连通就输出 0。
强制在线。

思路

看到连通想到并查集。

但是它要看什么时候连通,那我们就不能用路径压缩。
那我们考虑按秩合并,也就是启发式合并。

那就可以了。

代码

#include<cstdio>
#include<algorithm>

using namespace std;

int n, m, lst, op, x, y;
int fa[500001], sz[500001];
int tim[500001], ans, times;
bool met[500001];

int find(int now, int kk) {
	met[now] = kk;
	if (fa[now] == now) return now;
	return find(fa[now], kk);
}

int main() {
	scanf("%d %d", &n, &m);
	
	for (int i = 1; i <= n; i++)
		fa[i] = i, sz[i] = 1;
	
	while (m--) {
		scanf("%d %d %d", &op, &x, &y);
		x ^= lst; y ^= lst;
		
		if (op == 0) {
			times++;//边无论有没有用都要算进去边数(简称这行不能放在 X!=Y 里面)
			int X = find(x, 0), Y = find(y, 0);
			if (X != Y) {
				if (sz[X] > sz[Y]) swap(X, Y);//启发式合并,小的合并到大的中
				fa[X] = Y;
				sz[Y] += sz[X];
				tim[X] = times;
			}
			
			continue;
		}
		if (op == 1) {
			int X = find(x, 0), Y = find(y, 1);
			if (X != Y) {//不连通
				lst = 0;
				find(y, 0);//记得清空
				printf("0\n");
				continue;
			}
			
			ans = 0;
			while (!met[x]) {//只能计算跳到 LCA
				ans = max(ans, tim[x]);
				x = fa[x]; 
			}
			find(y, 0);//清空数组
			while (y != x) {//计算跳到 LCA
				ans = max(ans, tim[y]);
				y = fa[y];
			}
			
			lst = ans;
			printf("%d\n", lst);
			
			continue;
		}
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值