连通性询问
题目链接: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;
}