26 LCA模拟赛3T2 连边 题解
连边
题面
给定一张初始 \(n\) 个点,没有边的图。
给定 \(m\) 表示有 \(m\) 个时刻,第 \(i\) 个时刻会将 \(gcd(a,b) = m - i + 1\) 某些点连起来。
有 \(q\) 个询问,每次询问给定 \(x, y\),你需要回答 \(x, y\) 最早在什么时刻连通
\(1 \le n,q \le 10^5, 1 \le m \le n\)
题解
这个暴力思路就是直接模拟。
考虑优化,我们可以对原来加的边进行一个等价变形:每个时刻将 \(i\) 和 \(i\) 的倍数连边,边权为 \(i\) ,连通性是一样的。
这样,边数最多只有 \(O(n \log n)\) 。
我们对这些边按照边权从小到大加入到图中,用并查集维护连通性,从而构造出一棵最小生成树。
然后直接倍增查询路径最大边权即为答案。
时间复杂度 \(O(n \log n)\)
code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <map>
#include <set>
using namespace std;
namespace michaele {
const int N = 1e5 + 10, M = N << 1;
int n, m, q;
int h[N], ver[M], ne[M], e[M], tot;
int anc[N], f[N][23], g[N][23], dep[N];
void add (int x, int y, int z) {
ver[ ++ tot] = y;
ne[tot] = h[x];
h[x] = tot;
e[tot] = z;
}
int fin (int x) {
return x == anc[x] ? x : anc[x] = fin (anc[x]);
}
void dfs (int x, int fa) {
for (int i = h[x]; i; i = ne[i]) {
int y = ver[i];
if (y == fa) continue;
f[y][0] = x;
g[y][0] = e[i];
dep[y] = dep[x] + 1;
dfs (y, x);
}
}
int query (int x, int y) {
if (dep[x] < dep[y]) swap (x, y);
int res = 1;
for (int i = 20; i >= 0; i --) {
if (dep[f[x][i]] >= dep[y]) {
res = max (res, g[x][i]);
x = f[x][i];
}
}
if (x == y) return res;
for (int i = 20; i >= 0; i --) {
if (f[x][i] != f[y][i]) {
res = max ({res, g[x][i], g[y][i]});
x = f[x][i];
y = f[y][i];
}
}
res = max ({res, g[x][0], g[y][0]});
return res;
}
void solve () {
cin >> n >> m >> q;
for (int i = 1; i <= n; i ++) anc[i] = i;
for (int i = 1; i <= m; i ++) {
int k = m - i + 1;
for (int j = k * 2; j <= n; j += k) {
int x = fin (k), y = fin (j);
if (x != y) {
anc[x] = y;
add (k, j, i);
add (j, k, i);
}
}
}
dep[1] = 1;
dfs (1, 0);
for (int j = 1; j <= 19; j ++) {
for (int i = 1; i <= n; i ++) {
if (!f[i][j - 1]) continue;
f[i][j] = f[f[i][j - 1]][j - 1];
g[i][j] = max (g[i][j - 1], g[f[i][j - 1]][j - 1]);
}
}
for (int i = 1; i <= q; i ++) {
int x, y;
cin >> x >> y;
if (x == y) {
cout << 0 << endl;
continue;
}
cout << query (x, y) << endl;
}
}
}
int main () {
ios :: sync_with_stdio (0);
cin.tie (0);
cout.tie (0);
michaele :: solve ();
return 0;
}