BZOJ P2654 tree

来源:互联网 发布:linux下强制删除用户 编辑:程序博客网 时间:2024/06/03 15:59

神题啊

二分给白色边加上的权值,然后kruscal看看有没有正好need条边

有的话直接输出就可以了

然后证明的话不会,大概是你每条白边都加上一定的值是不会影响到最后的结果的

当然你也可以当做是显然成立的

#include<iostream>#include<algorithm>#include<cmath>#include<cstring>using namespace std;int n,m,cnt,tot,ned,sumv;int u[100005],v[100005],w[100005],c[100005];int fa[100005];struct edge{int u,v,w,c;}e[100005];bool operator<(edge a,edge b){if(a.w==b.w){return a.c<b.c;}else{return a.w<b.w;}}int find(int x){if(x==fa[x]){return x;}else{return fa[x]=find(fa[x]);}}void pre(int x){tot=cnt=0;for(int i=1;i<=n;i++){fa[i]=i;}for(int i=1;i<=m;i++){e[i].u=u[i]; e[i].v=v[i];e[i].w=w[i]; e[i].c=c[i];if(!c[i]){e[i].w+=x;}}}bool check(int x){pre(x);sort(e+1,e+m+1);for(int i=1;i<=m;i++){int p=find(e[i].u),q=find(e[i].v);if(p!=q){fa[p]=q;tot+=e[i].w;if(!e[i].c){cnt++;}}}return cnt>=ned;}int main(){cin>>n>>m>>ned;for(int i=1;i<=m;i++){cin>>u[i]>>v[i]>>w[i]>>c[i];u[i]++;v[i]++;}int l=-105,r=105;while(l<=r){int mid=(l+r)>>1;if(check(mid)){l=mid+1;sumv=tot-ned*mid;}else{r=mid-1;}}cout<<sumv<<endl;return 0;}


1 0
原创粉丝点击