BZOJ 2654 tree

2654: tree

Description

给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。题目保证有解。

Input

第一行V,E,need分别表示点数,边数和需要的白色边数。
接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。

Output

一行表示所求生成树的边权和。
V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。

Sample Input

2 2 1
0 1 1 1
0 1 2 0

Sample Output

2

  幸好保证有解,不然本人是很懵的。这道题目很有趣,值得去想一想。

  这道题,要求恰好取need条白色边,然后做最小生成树。平常,最小生成树是相对一定的。怎么办呢?

  注意到白边的优先级可以变化(排序时加减“虚”边权,统计时不加入),且存在着优先级与选取边数的单调性。我们让白边公平竞争,集体“虚”边权加减,二分其值([-105,105]),每一次再kruscal,看选取边数。最后输出结果。

  所以说,复杂度是二分O(lg n)*MST.O(nlg n)。

  

 1 /**************************************************************
 2     Problem: 2654
 3     User: Doggu
 4     Language: C++
 5     Result: Accepted
 6     Time:1520 ms
 7     Memory:3164 kb
 8 ****************************************************************/
 9  
10 #include <cstdio>
11 #include <algorithm>
12 template<class T>inline void readin(T &res) {
13     static char ch;T flag=1;while((ch=getchar())<'0'||ch>'9')if(ch=='-')flag=-1;
14     res=ch-48;while((ch=getchar())>='0'&&ch<='9')res=(res<<1)+(res<<3)+ch-48;res*=flag;
15 }
16 const int N = 100000+10;
17 const int M = 100000+10;
18 struct Edge {int u, v, w, col, add;}edges[M];
19 bool operator<(Edge a,Edge b) {return a.w+a.add<b.w+b.add;}
20 int n, m, need, fa[N];
21 int find(int x) {
22     if(fa[x]==x) return x;
23     return fa[x]=find(fa[x]);
24 }
25 int main() {
26     readin(n);readin(m);readin(need);
27     for( int i = 1; i <= m; i++ ) {
28         readin(edges[i].u);readin(edges[i].v);
29         readin(edges[i].w);readin(edges[i].col);
30     }
31     int lf=-105, rg=105, ans=0;
32     while(lf<=rg) {
33         int mid=(lf+rg)>>1, k=0, tot=0;
34         for( int i = 1; i <= m; i++ ) if(!edges[i].col) edges[i].add=mid;
35         for( int i = 0; i < n; i++ ) fa[i]=i;
36         std::sort(edges+1,edges+m+1);
37         for( int i = 1; i <= m; i++ ) {
38             if(find(edges[i].u)!=find(edges[i].v)) {
39                 if(!edges[i].col) k++;
40                 tot+=edges[i].w;
41                 fa[fa[edges[i].u]]=edges[i].v;
42             }
43         }
44         if(k>=need) ans=tot, lf=mid+1;
45         else rg=mid-1;
46     }
47     printf("%d\n",ans);
48     return 0;
49 }
二分+MST

 

 
posted @ 2017-07-05 09:37  Doggu  阅读(150)  评论(0编辑  收藏  举报