[BZOJ 2654]tree(陈立杰)
Description
Input
Output
Sample Input
0 1 1 1
0 1 2 0
Sample Output
Hint
V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。
题解
二分+$kruskal$
如果直接$kruskal$求最小生成树,是无法保证白边数量的,那么我们考虑如果改变白边的数量。我们可以把白边全部都加上一个权值,也就是我们二分的值,然后跑最小生成树,同时记录白边数量。当白边数量>=$need$时,$l=mid+1$,否则$r=mid−1$,更新答案就是这棵生成树的权值和减去所有白边的增量。
证明:
我们发现,如果我们给白边增加权值,做最小生成树,由于白边权值增大,导致不容易选白边。记$f(x)$为给白边增加$x$($x$可为负)权值,做最小生成树后,选白边的数量。可以发现,$f(x)$随$x$增大而减小,显然可以二分。
其次,我们发现,由于黑边的权值是不变的,与白边权值不相互影响。同样由于白边之间关系相对不变,必然选出的$need$条白边一定是符合题意的。
1 #include<map> 2 #include<ctime> 3 #include<cmath> 4 #include<queue> 5 #include<stack> 6 #include<cstdio> 7 #include<string> 8 #include<vector> 9 #include<cstring> 10 #include<cstdlib> 11 #include<iostream> 12 #include<algorithm> 13 #define LL long long 14 #define RE register 15 #define IL inline 16 using namespace std; 17 const int V=50000; 18 const int E=100000; 19 20 int mid; 21 int v,e,need,ans,cnt,tmp; 22 struct tt 23 { 24 int u,v,c,col; 25 }edge[E+5]; 26 27 IL int Kruskal(); 28 bool comp(const tt &a,const tt &b) {return a.c+(a.col^1)*mid<b.c+(b.col^1)*mid;} 29 30 int set[V+5]; 31 IL int find(int r) {return set[r]!=-1 ? set[r]=find(set[r]):r;} 32 33 int main() 34 { 35 scanf("%d%d%d",&v,&e,&need); 36 for (RE int i=1;i<=e;i++) scanf("%d%d%d%d",&edge[i].u,&edge[i].v,&edge[i].c,&edge[i].col); 37 int l=-100,r=100; 38 while (l<=r) 39 { 40 mid=(l+r)>>1; 41 if (Kruskal()>=need) l=mid+1,ans=tmp; 42 else r=mid-1; 43 } 44 printf("%d\n",ans); 45 return 0; 46 } 47 48 IL int Kruskal() 49 { 50 tmp=cnt=0; 51 int k=0; 52 memset(set,-1,sizeof(set)); 53 sort(edge+1,edge+1+e,comp); 54 for (RE int i=1;i<=e;i++) 55 { 56 int q=find(edge[i].u); 57 int p=find(edge[i].v); 58 if (p!=q) 59 { 60 k+=edge[i].col^1; 61 set[q]=p; 62 cnt++; 63 tmp+=edge[i].c; 64 if (cnt==v-1) break; 65 } 66 } 67 return k; 68 }
BZOJ能过的解法
感谢Hzoi_Maple!
由于$COGS$数据会有不满足恰好$need$条白边的情况
打个比方有这样的数据:加$0$时大于$need$,加$1$就小于$need$了。
这样应该在跑最小生成树的时候把所有的白边都加上加的那个权值,结果就是最小生成树的权值和减去$need*$加上的权值,多出来的那一部分完全可以当做黑边来看,因为数据是$100000$的,这样就可以了。(来自Hzoi_Maple)
排序的时候,如果边权相同,要把白边放在前面。
要计算当前至多能取多少白边,当然要把白边放前面。由于保证有解,在$cnt>=need$且$cnt$取最小值的方案下,一定能有黑边把多余的白边代替掉。
1 #include<map> 2 #include<ctime> 3 #include<cmath> 4 #include<queue> 5 #include<stack> 6 #include<cstdio> 7 #include<string> 8 #include<vector> 9 #include<cstring> 10 #include<cstdlib> 11 #include<iostream> 12 #include<algorithm> 13 #define LL long long 14 #define RE register 15 #define IL inline 16 using namespace std; 17 const int V=50000; 18 const int E=100000; 19 20 int mid; 21 int v,e,need,ans,cnt,tmp; 22 struct tt 23 { 24 int u,v,c,col,rc; 25 }edge[E+5]; 26 27 IL int Kruskal(); 28 IL void change(); 29 bool comp(const tt &a,const tt &b) {return a.rc==b.rc ? a.col<b.col:a.rc<b.rc;} 30 31 int set[V+5]; 32 IL int find(int r) {return set[r]!=-1 ? set[r]=find(set[r]):r;} 33 34 int main() 35 { 36 scanf("%d%d%d",&v,&e,&need); 37 for (RE int i=1;i<=e;i++) scanf("%d%d%d%d",&edge[i].u,&edge[i].v,&edge[i].c,&edge[i].col); 38 int l=-100,r=100; 39 while (l<=r) 40 { 41 mid=(l+r)>>1; 42 if (Kruskal()>=need) l=mid+1,ans=tmp-need*mid; 43 else r=mid-1; 44 } 45 printf("%d\n",ans); 46 return 0; 47 } 48 49 IL void change() 50 { 51 for (RE int i=1;i<=e;i++) edge[i].rc=edge[i].c+(edge[i].col^1)*mid; 52 } 53 IL int Kruskal() 54 { 55 change(); 56 tmp=cnt=0; 57 int k=0; 58 memset(set,-1,sizeof(set)); 59 sort(edge+1,edge+1+e,comp); 60 for (RE int i=1;i<=e;i++) 61 { 62 int q=find(edge[i].u); 63 int p=find(edge[i].v); 64 if (p!=q) 65 { 66 k+=edge[i].col^1; 67 set[q]=p; 68 cnt++; 69 tmp+=edge[i].rc; 70 if (cnt==v-1) break; 71 } 72 } 73 return k; 74 }
COGS能过的解法
转载于:https://www.cnblogs.com/NaVi-Awson/p/7252243.html
[BZOJ 2654]tree(陈立杰)相关推荐
- BZOJ2654: tree(陈立杰)
2654: tree(陈立杰) Time Limit: 30 Sec Memory Limit: 512 MB Submit: 229 Solved: 91 [Submit][Status] De ...
- [国家集训队2012]tree(陈立杰)
1764. [国家集训队2012]tree(陈立杰) ★★★ 输入文件: nt2012_tree.in 输出文件: nt2012_tree.out 简单对比 时间限制:3 s 内存限 ...
- bzoj 2653: middle(陈立杰)
首先膜拜clj... 这道题初看没头绪,看了诸多题解后,发现时先二分,在把大于等于它的为1,小于它的为-1,一段区间最大连续和非负就行 然后想了N久都没想通,终于,在昨天在外拜年时想通了,就是以每个数 ...
- tree(陈立杰)[国家集训队2012]
时间限制:3.0s 内存限制:1.0GB [大意] 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解. [输入格式] 第一行V,E,ne ...
- 最小生成树 tree(陈立杰)
问题 D: tree 时间限制: 3 Sec 内存限制: 512 MB 提交: 24 解决: 7 [提交][状态][讨论版] 题目描述 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰 ...
- BZOJ2654/COGS1764 [2012国家集训队]tree(陈立杰) [生成树,二分]
BZOJ传送门,COGS传送门 tree Description 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解. Input 第一行V, ...
- 姚班学霸陈立杰:16岁保送清华,18岁拿下IOI世界冠军,现摘得FOCS 2019最佳学生论文...
郭一璞 安妮 发自 凹非寺 量子位 出品 | 公众号 QbitAI 今年的理论计算机顶会FOCS,一位来自浙江湖州的小哥哥一口气中了3篇论文,还拿下了最佳学生论文奖. 而且这不是偶然神迹,类似操作, ...
- 陈立杰再获FOCS 2019最佳学生论文奖
来源:量子星图 本文约700字,建议阅读5分钟. 在计算机科学顶级会议FOCS 2019上,陈立杰"连中三元",共有三篇论文入围,是入围论文最多的研究者之一. 9月7日,第60届I ...
- 姚班大神陈立杰最新动向:MIT毕业后将进入诺奖摇篮,成为UC伯克利Miller研究员...
晓查 发自 凹非寺 量子位 | 公众号 QbitAI 据知情人士透露,陈立杰今从MIT博士毕业后,将加入加州大学伯克利分校,成为该校Miller研究所研究员. 陈立杰是清华大学姚班知名校友,2016年 ...
最新文章
- python十进制转八进制_怎样用python进行二进制,八进制,十进制转换
- 更改eclipse的Package Explorer的字体
- python Hbase Thrift pycharm 及引入包
- 成幻Online Judge 1.00 Beta 正式发布 2007.6.22
- 限制Apache日志access.log、error.log文件大小
- 本期最新 9 篇论文,每一篇都想推荐给你 | PaperDaily #14
- velocity参数重新赋值_Velocity(5)——#set指令
- 7-n!末尾有几个0
- PHP memory_get_usage()管理内存
- Oracle基本安全之用户、角色和权限操作
- 【底层原理】深入理解Cache (上)
- 直播教程 || 虚拟直播设备清单分享,建议收藏~
- linux 查看硬盘序号,Linux 查看硬盘序列号 命令
- matlab解隐式差分格式,【毕业设计(论文)】二维热传导方程有限差分法的MATLAB实现...
- JQuery读取txt文件
- PC端如何双开/多开微信(实测可用)
- WSUS无法发现客户端
- Leetcode-机器人大冒险 (python)
- Atitit q2016 qb doc list on home ntpc.docx
- 感恩陪伴,链接未来 | Conflux杭州应用开发运营中心成立
热门文章
- 在Linux下编写C程序,怎么检查程序是否有内存泄漏?
- [react-router] React-Router 4怎样在路由变化时重新渲染同一个组件?
- [react] 使用高阶组件(HOC)实现一个loading组件
- React开发(204):react代码分割之路由懒加载
- Taro+react开发(36)每一个节点要一个view包裹
- 前端学习(3278):循环 遍历
- react学习(5)----通过设置初始值控制页面render渲染
- [html] 写一个类似刮刮卡效果的交互,即鼠标划过时显示号码
- [css] 颜色hsla的字母分别表示什么?
- 工作284:理解绑定逻辑