题目大意:

给一棵树。求用最少的链覆盖这棵树(链不能相交),在这个基础上求最长的链最短可以是多少。

n<=10000

题解:

肯定先处理第一问:

答案:$\sum_(du[i]-1)/2+1$

证明:

1.对于一个非根的节点x,x的每一个到儿子的边必须被覆盖。

只有两种可能:要么这个链不超过x,要么从x头上进来。

发现,从x头上进来的链有且只有一个。

如果x的儿子数量是偶数,肯定只能把边两两配对。如果奇数,那么剩下这一个就和从x头上下来的链在一起即可。

儿子数du[i]-1,花费:(du[i]-1)/2

2.对于根节点rt

儿子偶数的话,同理,如果儿子是奇数的话,由于rt没有从头上下来的链,只能单独算作一个链。

所以答案是:(du[i]+1)/2,即(du[i]-1)/2+1

证毕。

第二问:

二分答案显然。

判定mid:我们既要满足最长小于等于mid,还要满足贪心方法依然能使得链数最小。

根据刚才第一问的分析,子树x的对于儿子的覆盖情况无非就那么两种。而且x内的覆盖情况对其他子树的影响只有从x上去的那一条链。

而比较麻烦的是x头上下来的链。发现,这个链只有一个。

所以,我们在x子树内合法覆盖、用的链最少的前提下,想头上的链越短越有利。

f[x]表示 ,x头上的链的最短长度。

或者更准确地说,x头上的链进入x子树后,还要延伸多少。

dfs时,

对于x,我们先求出f[son]

然后想办法求f[x]

把f[son]+1计入mem数组,然后从小到大排序。

如果x有奇数个儿子,二分f[x]位置,然后大小配对。

如果x有偶数个儿子,如果可以大小直接配对,完事大吉,f[x]=0,然后回溯。

否则,二分f[x]位置,然后把剩下的最大的f[son]+1独自一条链(这样也可以满足方案数最小的)

继续大小配对判断。

当然,对于根节点,f[x]没有意义了,就检查一下,如果偶数个儿子,直接配对。奇数个,去掉最大的配对。

任何时候,如果f[son]+1>mid,或者f[x]不存在,或者根节点匹配失败,都return false

所以,其实是大二分,然后dfs贪心的时候再二分。

代码:

注意两个mid不要弄混。。。。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=+;
int n;
struct node{
int nxt,to;
}e[*N];
int hd[N],cnt;
void add(int x,int y){
e[++cnt].nxt=hd[x];
e[cnt].to=y;
hd[x]=cnt;
}
int son[N],tot;
int mid;
int ans1,ans2;
int du[N];
bool fl;
int f[N];
void dfs(int x,int fa){
//cout<<x<<" "<<fa<<endl;
if(!fl) return;//warning!!!
for(int i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa) continue;
dfs(y,x);
}
tot=;
if(!fl) return;//warning!!
for(int i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa) continue;
son[++tot]=f[y]+;
}
sort(son+,son+tot+);
//cout<<x<<" 's son "<<endl;
//for(int i=1;i<=tot;i++) cout<<son[i]<<" ";cout<<endl;
if(son[tot]>mid) {fl=false;return;}//warning!!!
if(x==){
bool can=true;
if(tot%==) tot--;
for(int i=;i<=tot/;i++){
if(son[i]+son[tot-i+]>mid){
can=false;break;
}
}
if(!can) fl=false;
}
else{
if(tot%==){
bool can=true;
for(int i=;i<=tot/;i++){
if(son[i]+son[tot-i+]>mid){
can=false;break;
}
}
if(can) {
f[x]=;return;//warning!!!!! has returned
}
}
f[x]=-;//warning!!!
int L=,R=tot;
while(L<=R){
int M=(L+R)>>;
int up=tot;
if(M==tot) up--;
if(tot%==) up--;
bool can=true;
for(int i=;i<=up;i++){
if(i==M) continue;
if(son[i]+son[up]>mid) {
can=false;break;
}
up--;
}
//cout<<x<<" M "<<M<<" : "<<can<<endl;
if(can) f[x]=son[M],R=M-;
else L=M+;
}
if(f[x]==-) {
fl=false;
}
}
}
bool che(){
fl=true;
//cout<<" mid "<<mid<<" ------------------"<<endl;
memset(f,,sizeof f);
dfs(,);
//cout<<" ff "<<endl;
//for(int i=1;i<=n;i++){
/// cout<<i<<" : "<<f[i]<<endl;
//}
return fl;
}
int main(){
scanf("%d",&n);int x,y;
for(int i=;i<=n-;i++){
scanf("%d%d",&x,&y);add(x,y);add(y,x);
du[x]++,du[y]++;
}
for(int i=;i<=n;i++){
ans1+=(du[i]-)/;
}
ans1++;
int l=,r=n-;
while(l<=r){
mid=(l+r)>>;
if(che()){
ans2=mid,r=mid-;
}
else l=mid+;
}
printf("%d %d",ans1,ans2);
return ;
}

总结:

树上贪心肯定和儿子有关系。

观察覆盖x到儿子的边的两种方案。结合二分贪心


$upda:2018.12.29$

NOIP考到了这个题目,几乎是原题,而且没有第一问。。。。

大致的思路是对的。

但是二分里面的二分没有写上,,(反而写了儿子个数平方套set?)

看来写题目不光是思路要有,关键的trick也不能放过

(对了感谢ywy_c_asm神犇,多亏了他给我推荐SZN这个题,否则NOIP就GG了)

2067: [Poi2004]SZN——树上贪心+二分的更多相关文章

  1. bzoj 2067: [Poi2004]SZN【贪心+二分+树形dp】

    第一问就是Σ(deg[u]-1)/2+1 第二问是二分,判断的时候考虑第一问的贪心规则,对于奇度数的点,两两配对之后一条延伸到上面:对于欧度数的点,两两配对或者deg[u]-2的点配对,然后一条断在这 ...

  2. bzoj 2067 [Poi2004]SZN——二分+贪心

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2067 最少的线段可以贪心地想出来.(结果还是写错了)就是偶数孩子可以自己配对,奇数孩子要带一 ...

  3. 【BZOJ2067】[Poi2004]SZN 二分+树上贪心

    [BZOJ2067][Poi2004]SZN Description String-Toys joint-stock 公司需要你帮他们解决一个问题. 他们想制造一个没有环的连通图模型. 每个图都是由一 ...

  4. bzoj 2525: [Poi2011]Dynamite【二分+树上贪心】

    一眼二分.然后重点是树上贪心部分 长得像dp一样,设mn为子树内已炸点的最浅点,mx为子树内没有炸并且需要炸的最深点,然后转移直接从子树继承即可 然后是判断当前u点是否需要炸,当mx[u]+mn[u] ...

  5. 【BZOJ2067】[Poi2004]SZN

    题解: 比上一题水多了 首先树上贪心,肯定要考虑儿子 然后我们会发现这个东西就是要先把儿子连起来 然后如果儿子个数为奇数我们可以把这一条和它连向父亲的并在一起 由于根没有父亲所以要单独考虑 答案就是s ...

  6. poj 2782 Bin Packing (贪心+二分)

    F - 贪心+ 二分 Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu   Description ...

  7. Card Game Cheater(贪心+二分匹配)

    Card Game Cheater Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  8. The 14th Zhejiang Provincial Collegiate Programming Contest Sponsored by TuSimple - F 贪心+二分

    Heap Partition Time Limit: 2 Seconds      Memory Limit: 65536 KB      Special Judge A sequence S = { ...

  9. 贪心/二分查找 BestCoder Round #43 1002 pog loves szh II

    题目传送门 /* 贪心/二分查找:首先对ai%=p,然后sort,这样的话就有序能使用二分查找.贪心的思想是每次找到一个aj使得和为p-1(如果有的话) 当然有可能两个数和超过p,那么an的值最优,每 ...

随机推荐

  1. 韦大仙--python对文件操作 2--写入与修改

    请大家看一段代码: yesterday2是我之前上个帖子创建的文件,为了方便大家看清我把本来的代码复制到下面: coding=utf-8 f=open("yesterday2",& ...

  2. EditorGUI控件输入监听

    EditorGUI控件输入监听 在做编辑器开放的过程中,有时候要对用户输入进行判断和限制,但EditorGUI控件却没有触发回调,而是提供了一种麻烦的办法--使用EditorGUI.BeginChan ...

  3. Vue 编程之路(二)——跳转页面传值

    最近公司的一个项目中使用 Vue 2.0 + element UI 实现一个后台管理系统的前端部分,属于商城类型.其中我负责的部分有一项需要跳转页面,由于跳转前的页面是多个组件构成的,所以在跳转页面的 ...

  4. python常用命令—查看模块所在位置

    环境:ipython3 交互式解释器 语法: import 模块名 模块名.__file__ 功能: 查看模块的所在位置 例:

  5. LeetCode 94 ——二叉树的中序遍历

    1. 题目 2. 解答 2.1. 递归法 定义一个存放树中数据的向量 data,从根节点开始,如果节点不为空,那么 递归得到其左子树的数据向量 temp,将 temp 合并到 data 中去 将当前节 ...

  6. Halcon图像采集助手提示找不到指定DLL文件

    问题原因: Halcon软件更新导致某些图像采集DLL失效,这个时候就需要去MVTEC官网下载图像采集接口补丁程序,MVTEC官网地址http://www.mvtec.com/. 对于其他模块失效的D ...

  7. 官方文档 恢复备份指南一 Introduction to Backup and Recovery

    1.备份分为:物理备份和逻辑备份    物理备份:备份数据文件  控制文件  归档日志文件     逻辑备份:EXP EXPDP备份等 物理备份为主,逻辑做补充     2.错误的类型         ...

  8. js经典试题之数组与函数

    js经典试题之数组与函数 1:列举js的全局函数? 答案:JavaScript 中包含以下 7 个全局函数escape( ).eval( ).isFinite( ).isNaN( ).parseFlo ...

  9. "Hello world!"团队第一次会议

    今天是我们"Hello world!"团队第一次召开会议,今天的会议可能没有那么正式,但是我们一起确立了选题——基于WEB的售票系统.博客内容是: 1.会议时间 2.会议成员 3. ...

  10. Thunder团队第三周 - Scrum会议7

    Scrum会议7 小组名称:Thunder 项目名称:i阅app Scrum Master:胡佑蓉 工作照片: 邹双黛在照相,所以图片中没有该同学. 参会成员: 王航:http://www.cnblo ...