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;
} 

 

posted @ 2019-10-14 07:27  水题收割者  阅读(200)  评论(0编辑  收藏  举报