- 给你一张图,若干次查询,每次查询询问
[
l
,
r
]
[l,r]
[l,r]之间所有点对,问最少需要前几条边能够使点联通
- 基础好题,很巧妙,首先建立
k
r
u
s
k
a
l
kruskal
kruskal重构树,新添加的节点的点权表示它是第几条边,然后用
S
T
ST
ST表维护
[
i
,
i
+
1
]
[i,i+1]
[i,i+1]的
L
C
A
LCA
LCA的点权,区间查询最大值即可得出答案
- 为什么这样是对的呢?根据
k
r
u
s
k
a
l
kruskal
kruskal重构树的性质,这些节点一定是编号较小的,连续区间内任意两点的
L
C
A
LCA
LCA一定包含在若干个
[
i
,
i
+
1
]
[i,i+1]
[i,i+1]的
L
C
A
LCA
LCA内部,因为是一个连通图
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct DSU{
int n;
vector<int> s;
DSU(int _n): n(_n){
s.resize(n);
iota(s.begin(), s.end(), 0);
}
int FIND(int x){
return x == s[x] ? x : s[x] = FIND(s[x]);
}
};
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--){
int n, m, q;
cin >> n >> m >> q;
DSU dsu(2 * n);
vector<int> dep(2 * n);
vector<int> val(2 * n);
vector<vector<int> > g(2 * n);
vector<vector<int> > fa(2 * n, vector<int>(30));
vector<vector<int> > ST(2 * n, vector<int>(30));
for(int i=0;i<m;i++){
int u, v;
cin >> u >> v;
u -= 1;
v -= 1;
u = dsu.FIND(u);
v = dsu.FIND(v);
if(u != v){
dsu.s[u] = dsu.s[v] = n;
g[n].push_back(u);
g[n].push_back(v);
val[n] = i + 1;
n += 1;
}
}
n -= 1;
function<void(int, int)> Dfs = [&](int u, int d){
dep[u] = d;
for(auto v : g[u]){
fa[v][0] = u;
Dfs(v, d + 1);
}
};
Dfs(n, 1);
function<int(int, int)> LCA = [&](int u, int v){
if(dep[u] < dep[v]) swap(u, v);
for(int i=log2(dep[u] - dep[v]);i>=0;i--){
if((1 << i) <= dep[u] - dep[v]){
u = fa[u][i];
}
}
if(u == v) return val[u];
for(int i=log2(dep[u]);i>=0;i--){
if(fa[u][i] != fa[v][i]){
u = fa[u][i];
v = fa[v][i];
}
}
return val[fa[u][0]];
};
for(int j=1;j<30;j++){
for(int i=0;i<n;i++){
fa[i][j] = fa[fa[i][j - 1]][j - 1];
}
}
for(int i=0;i<n-1;i++){
ST[i][0] = LCA(i, i + 1);
}
for(int j=1;j<=log2(n);j++){
for(int i=0;i+(1<<(j-1))<n;i++){
ST[i][j] = max(ST[i][j - 1], ST[i + (1 << (j - 1))][j - 1]);
}
}
function<int(int, int)> Get = [&](int l, int r){
int len = r - l + 1;
int sz = log2(len);
return max(ST[l][sz], ST[r - (1 << sz) + 1][sz]);
};
for(int i=0;i<q;i++){
int l, r;
cin >> l >> r;
l -= 1;
r -= 1;
if(l == r){
cout << 0 << " \n"[i == q - 1];
}else{
r -= 1;
cout << Get(l, r) << " \n"[i == q - 1];
}
}
}
return 0;
}