p2619 [国家集训队2]Tree I [wqs二分学习]
分析
https://www.cnblogs.com/CreeperLKF/p/9045491.html
反正这个博客看起来很nb就对了
但是不知道他在说啥
实际上wqs二分就是原来的值dp[x]表示选x个的最优解满足是一个凸包
然后就可以二分一个数
让有限制的一类数全部给权值加上这个二分的数
然后判断即可
这个题就是典型的模板题
代码
#include<bits/stdc++.h>
using namespace std;
const int inf = 1e9+7;
int n,m,sum,res,cnt,tot,fa[100100];
struct node {
int x,y,z,col;
};
node d[100100],d1[100100];
inline int sf(int x){return fa[x]==x?x:fa[x]=sf(fa[x]);}
inline bool cmp(const node x,const node y){return x.z==y.z?x.col<y.col:x.z<y.z;}
inline int ck(int mid){
int i,j,k;
for(i=1;i<=m;i++)d[i]=d1[i];
for(i=1;i<=m;i++)if(!d[i].col)d[i].z+=mid;
res=tot=cnt=0;
for(i=1;i<=n;i++)fa[i]=i;
sort(d+1,d+m+1,cmp);
for(i=1;i<=m;i++){
int x=d[i].x,y=d[i].y;
if(sf(x)!=sf(y)){
fa[sf(x)]=sf(y);
cnt++;
res+=d[i].z;
if(!d[i].col)tot++;
}
if(cnt==n-1)break;
}
return tot;
}
int main(){
int i,j,k,le=-200,ri=200;
scanf("%d%d%d",&n,&m,&sum);
for(i=1;i<=m;i++)scanf("%d%d%d%d",&d1[i].x,&d1[i].y,&d1[i].z,&d1[i].col),d1[i].x++,d1[i].y++;
while(ri-le>1){
int mid=(le+ri)>>1;
if(ck(mid)>=sum)le=mid;
else ri=mid;
}
ck(le);
printf("%d\n",res-sum*le);
return 0;
}