[WQS二分] BZOJ2654:tree
2017-12-19 18:25
393 查看
以前做这题的时候以为只是个神奇的二分,没有完全懂原理,现在发现实际上就是 WQS 二分。
考虑 g(x) 表示选共 x 条白边的最优解,可以感觉到这个 g(x) 应是上凸的,满足斜率不降。所以就 WQS 二分就好了。
考虑 g(x) 表示选共 x 条白边的最优解,可以感觉到这个 g(x) 应是上凸的,满足斜率不降。所以就 WQS 二分就好了。
#include<cstdio> #include<algorithm> using namespace std; const int maxn=100005; int n,m,K; int ans,res,cnt,mid; struct data{ int x,y,z,k; } a[maxn]; bool _cmp(const data &A,const data &B){ if(A.z+(A.k?0:mid)==B.z+(B.k?0:mid)) return A.k<B.k; return A.z+(A.k?0:mid)<B.z+(B.k?0:mid); } int fa[maxn]; int getfa(int x){ return fa[x]==x?x:fa[x]=getfa(fa[x]); } bool check(){ res=0; cnt=0; for(int i=1;i<=n;i++) fa[i]=i; sort(a+1,a+1+m,_cmp); for(int i=1;i<=m;i++){ if(getfa(a[i].x)==getfa(a[i].y)) continue; fa[getfa(a[i].x)]=getfa(a[i].y); res+=a[i].z; if(!a[i].k) cnt++; } return cnt>=K; } int main(){ scanf("%d%d%d",&n,&m,&K); for(int i=1;i<=m;i++) scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].z,&a[i].k), a[i].x++, a[i].y++; int L=-105,R=105; while(L<=R){ mid=(L+R)>>1; if(check()) L=mid+1, ans=res; else R=mid-1; } printf("%d\n",ans); return 0; }
相关文章推荐
- [BZOJ2654][tree][二分+Kruskal]
- bzoj2654 tree(二分+kruskal)
- [Kruscal 二分] BZOJ 2654 tree
- [BZOJ2654]tree(二分+MST)
- 【二分+最小生成树】BZOJ2654 tree
- BZOJ 2654: tree kruskal 二分
- bzoj2654: tree(二分+最小生成树)
- 【二分+最小生成树】BZOJ2654[tree]题解
- [bzoj2654]tree(最小生成树+二分)
- bzoj 2654: tree (二分+最小生成树)
- 【BZOJ2654】tree【二分】【最小生成树】
- BZOJ 2654 tree 二分答案+Kruskal
- 【BZOJ】2654 tree 二分+kruskal
- 【bzoj2654】【二分+最小生成树】tree
- BZOJ 2654 tree 二分+最小生成树
- [bzoj2654]tree_二分_kruskal
- BZOJ 2654 tree(二分答案+最小生成树)
- 【二分+最小生成树】bzoj2654 tree
- BZOJ 2654: tree( 二分 + MST )
- BZOJ 2654 tree(二分答案+并查集)