纯菜鸡只写出了两题,菜完了,不想当分母呀TAT
H. Minimum Spanning Tree

自己能思考到的:最小生成树的唯一性
不能思考到:只有i和i-1才有必要被新添加进去,将原本的图的边进行排序,代价为0或者1的必然不会更优了,所以能加就加,至少要加n-1-k条,若为01则加到不能加为止,先跑对有限的边一遍**克鲁斯卡尔,**然后再用最优的加边方式(i和i+1)加到整个图联通(n-1条),最后输出答案即可
上代码:
cpp
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define endl '\n'
using namespace std;
typedef pair<int,int>pii;
const int N=5e5+10;
int p[N];
struct nod{
int u,v,w,id;
bool operator<(const nod& b)const{
return w<b.w;
}
};
int find(int x){
if(x==p[x]) return x;
return p[x]=find(p[x]);
}
bool merge(int a,int b){
int x=find(a),y=find(b);
if(x==y) return 0;
p[y]=x;
return 1;
}
void solve(){
int n,m,k;cin>>n>>m>>k;
for(int i=1;i<=n;i++) p[i]=i;
vector<nod>edg(1);
for(int i=1;i<=m;i++){
int u,v,w;cin>>u>>v>>w;
edg.push_back({u,v,w,i});
}
sort(edg.begin()+1,edg.end());
vector<nod>res;
int ans=0,cnt=0;
int must=n-1-k;
for(int i=1;i<=m&&cnt<n-1;i++){
auto [u,v,w,id]=edg[i];
if(w<=1){
if(merge(u,v)){
cnt++;
ans+=w;
res.push_back(edg[i]);
}
continue;
}
if(cnt>=must){
break;
}
if(merge(u,v)){
cnt++;
ans+=w;
res.push_back(edg[i]);
}
}
vector<nod>add;
int idx=m+1;
int ad=0;
for(int i=1;i<=n-1;i++){
if(cnt==n-1) break;
if(ad==k) break;
if(merge(i,i+1)){
cnt++;
ad++;
ans+=1;
add.push_back({i,i+1,1,idx});
idx++;
}
}
cout<<ad<<endl;
for(auto [u,v,w,id]:add){
cout<<u<<" "<<v<<endl;
}
cout<<ans<<endl;
for(auto [u,v,w,id]:res){
cout<<id<<" ";
}
for(auto [u,v,w,id]:add){
cout<<id<<" ";
}
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);
int T=1;cin>>T;
while(T--){
solve();cout<<endl;
}
}