思路:
按边权由小到大合并边的两个顶点,假设当前需要操作的边为,则:
如果和已经在同一个组里了就不用继续合并了
如果和不在同一个组里,就将和所在的组合并,则到存在一条路径上的最大值就是,且找不到比其他的路径满足该路径上的最大值小于,因为和目前只有这一条路径(边),那么
每一阶段取出同权值的所有边,将这些边的端点用并查集两两合并,待合并完这一阶段的全部边,并查集数量为,那么当前阶段合并边的权值就是答案,否则输出。也就是说同权值的所有边要同时合并,因为未被合并的边的权值需要满足(因为题目要求和 之间不可能有任何路径满足该路径中的最大值小于或等于 。)
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; }