KD-Graph
思路:
按边权由小到大合并边的两个顶点,假设当前需要操作的边为
(
x
,
y
,
v
a
l
)
{(x,y,val)}
(x,y,val),则:
如果
x
{x}
x和
y
{y}
y已经在同一个组里了就不用继续合并了
如果
x
{x}
x和
y
{y}
y不在同一个组里,就将
x
{x}
x和
y
{y}
y所在的组合并,则
x
{x}
x到
y
{y}
y存在一条路径上的最大值就是
v
a
l
{val}
val,且找不到比其他的路径满足该路径上的最大值小于
v
a
l
{val}
val,因为
x
{x}
x和
y
{y}
y目前只有这一条路径(边),那么
D
>
=
v
a
l
{D>=val}
D>=val
每一阶段取出同权值的所有边,将这些边的端点用并查集两两合并,待合并完这一阶段的全部边,并查集数量为
k
{k}
k,那么当前阶段合并边的权值就是答案,否则输出
−
1
{-1}
−1。也就是说同权值的所有边要同时合并,因为未被合并的边的权值需要满足
v
a
l
>
D
{val>D}
val>D(因为题目要求
p
{p}
p和
q
{q}
q 之间不可能有任何路径满足该路径中的最大值小于或等于
D
{D}
D。)
code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 7,maxm=5e5+7;
int fa[maxn],n,m,k;
set<int>st;
unordered_map<int,int>mp;
vector<pair<int,int> >v[maxm];
inline int find(int x) {
return x==fa[x]?x:(fa[x]=find(fa[x]));
}
inline void solve() {
cin>>n>>m>>k;
int cnt=n,ans=-1,x,y,tot(0);
for(int i=1;i<=n;++i) fa[i]=i;
for(auto i:st) v[mp[i]].clear();
st.clear(); mp.clear();
for(int i=1,c;i<=m;++i) {
cin>>x>>y>>c;
if(!mp.count(c)) mp[c]=++tot;
st.insert(c);
v[mp[c]].emplace_back(make_pair(x,y));
}
if(n==k) return printf("0\n"),void();
for(auto i:st) {
for(auto j:v[mp[i]]) {
x=find(j.first),y=find(j.second);
if(x!=y) {
fa[y]=x; --cnt;
}
}
if(cnt==k) return printf("%d\n",i),void();
if(cnt<k) return printf("-1\n"),void();
}
printf("-1\n");
}
int main() {
// freopen("1.txt","r",stdin);
// freopen("brute.txt","w",stdout);
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int T,n,m,k;
cin>>T;
while(T--) solve();
return 0;
}