有关于wqs二分的问题,一般伴随着选指定个数的数量,且数量选取的多少和方法都会影响答案的一种问题。
这种问题一般都具有凸性,也就是斜率单增单减,这样我们就可以套上wqs二分来优化。
这基于的原理可以观看wqs本人的论文。
对于这题,我们发现选取白边的数量对答案是由影响的,也可以证明他确实具有凸性。
我们二分权值,对于每个白边都加上这个权值,之后做一遍最小生成树。如果使用的白边数量不够,说明我们需要往左边二分,也就是我们希望白边的个数增多。
反之就往右边二分,但是很多题目这样二分是可能出不了结果的,这是因为,我们附加的权值即使变化1,白边数量不一定变化1,因为我们可能在相同权值的白边和黑边上选择了黑边。
因此我们考虑排序,将白边先选,这样我们肯定可以刚好变化成要求数量。很多题目都要像这样附加一个条件。

#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ll,ll> pll; const int N=2e6+10; const int M=2e6+10; const int inf=0x3f3f3f3f; int p[N],n,m,k; ll ans; struct node{ int a,b,c,id; }e[N],s[N]; bool cmp(node a,node b){ if(a.c==b.c) return a.id<b.id; else return a.c<b.c; } int find(int x){ if(p[x]!=x){ p[x]=find(p[x]); } return p[x]; } int check(int x){ int i; int tot=0; int cnt=0; ans=0; for(i=1;i<=m;i++){ s[i]=e[i]; if(e[i].id==0) s[i].c+=x; } for(i=1;i<=n;i++) p[i]=i; sort(s+1,s+1+m,cmp); for(i=1;i<=m;i++){ int pa=find(s[i].a); int pb=find(s[i].b); if(pa!=pb){ tot++; if(!s[i].id) cnt++; p[pa]=pb; ans+=s[i].c; } if(tot==n-1) break; } return cnt>=k; } int main(){ ios::sync_with_stdio(false); int i; cin>>n>>m>>k; for(i=1;i<=m;i++){ cin>>e[i].a>>e[i].b>>e[i].c>>e[i].id; e[i].a++; e[i].b++; } int l=-100,r=100; int us=0; while(l<r){ int mid=l+r+1>>1; if(check(mid)){ l=mid; } else r=mid-1; } check(l); cout<<ans-l*k<<endl; }