剪辣椒(chilli)

题目描述

在花园里劳累了一上午之后,你决定用自己种的干辣椒奖励自己。

你有n个辣椒,这些辣椒用n-1条绳子连接在一起,任意两个辣椒通过用若干个绳子相连,即形成一棵树。

你决定分三餐吃完这些辣椒,因此需要剪断其中两根绳子,从而得到三个组成部分,每一餐吃一个组成部分即可。



每一餐不可以太辣,所以你会寻找一个剪绳子的方法,使得最大组成部分和最小组成部分的辣椒数量差最小。计算出这个最小差值。

输入格式

输入文件名为chilli.in。

第一行一个整数n,表示辣椒的数量。辣椒从1到n进行编号。

下面n-1行每一行包含两个整数x和y(1≤x,y≤n),表示辣椒x和辣椒y直接用一根绳子相连。

输出格式

输出文件名为chilli.out。

输出最小差值。

题解

题目大意:删掉一棵树上的两条边使得形成的三棵树里\(size\)最大的减\(size\)最小的差值最小,问最小差值

先求出以每个点为根的子树的大小\(size_i\)(假定1为整棵树的根)

然后枚举每个点(用\(dfs\),在到每个点的时候就计算贡献,即删除当前点与父亲的边,做完之后把\(n-size_x\)加到\(set\),结束后从\(set\)中移除),删掉它与它父亲的边,这时将整棵树分成两部分:\(size_x\)和\(n-size_x\),然后在\(n-size_x\)里找到\(\lceil\dfrac{n-size_x}{2}\rceil\)的前驱后继,这里可以用\(set\)里的\(lower\_bound\)(不会用\(set\)可以自行搜索,这里推荐一篇写的比较好的文章https://blog.csdn.net/qq_34243930/article/details/81481929)。关于另一条边,有两种情况,一种是祖先边,上面已经计算,另一种是非祖先边,可以再用一个\(dfs\),但与上面有所不同,这里是删除当前点与儿子的边,然后结束后加入\(size_x\)

Code

#include<set>
#include<cstdio>
#include<cstring>
#include<iostream>
#define inf 2147483600
using namespace std;
struct node
{
int next,to,head;
}a[400001];
int n,x,y,ans,tot,size[200001];
multiset<int> q;
multiset<int>::iterator it;
void add(int x,int y)
{
a[++tot].to=y;
a[tot].next=a[x].head;
a[x].head=tot;
}
void getsize(int now,int fa)
{
size[now]=1;
for (int i=a[now].head;i;i=a[i].next)
{
if (a[i].to==fa) continue;
getsize(a[i].to,now);
size[now]+=size[a[i].to];
}
}
int getans(int x,int y,int z) {return max(x,max(y,z))-min(x,min(y,z));}
void calc(int x)
{
int p=n-size[x];
it=q.lower_bound((p+1)>>1);
if (it!=q.end()) ans=min(ans,getans(size[x],p-*it,*it));
if (it!=q.begin()) it--,ans=min(ans,getans(size[x],p-*it,*it));
it=q.lower_bound(max(size[x],p-size[x]));
if (it!=q.end()) ans=min(ans,*it*2-p);
}
void dfs1(int now,int fa)
{
calc(now);
q.insert(n-size[now]);
for (int i=a[now].head;i;i=a[i].next)
{
if (a[i].to==fa) continue;
dfs1(a[i].to,now);
}
q.erase(n-size[now]);
}
void dfs2(int now,int fa)
{
for (int i=a[now].head;i;i=a[i].next)
{
if (a[i].to==fa) continue;
calc(a[i].to);
dfs2(a[i].to,now);
}
q.insert(size[now]);
}
int main()
{
freopen("chilli.in","r",stdin);
freopen("chilli.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<n;++i)
{
scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
ans=inf;
getsize(1,0);
dfs1(1,0);
dfs2(1,0);
printf("%d\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}

【2020.11.30提高组模拟】剪辣椒(chilli)的更多相关文章

  1. 【2020.11.30提高组模拟】删边(delete)

    删边(delete) 题目 题目描述 给你一棵n个结点的树,每个结点有一个权值,删除一条边的费用为该边连接的两个子树中结点权值最大值之和.现要删除树中的所有边,删除边的顺序可以任意设定,请计算出所有方 ...

  2. 【2020.11.28提高组模拟】T1染色(color)

    [2020.11.28提高组模拟]T1染色(color) 题目 题目描述 给定 \(n\),你现在需要给整数 \(1\) 到 \(n\) 进行染色,使得对于所有的 \(1\leq i<j\leq ...

  3. 【2020.11.28提高组模拟】T2 序列(array)

    序列(array) 题目描述 ​给定一个长为 \(m\) 的序列 \(a\). 有一个长为 \(m\) 的序列 \(b\),需满足 \(0\leq b_i \leq n\),\(\sum_{i=1}^ ...

  4. 【2020.12.03提高组模拟】A组反思

    估计:40+10+0+0=50 实际:40+10+0+0=50 rank40 T1 赛时看到\(n,m\leq9\),我当机立断决定打表,暴力打了几个点之后发现在\(n\ne m\)且\(k\ne0\ ...

  5. 11.5NOIP2018提高组模拟题

    书信(letter) Description 有 n 个小朋友, 编号为 1 到 n, 他们每人写了一封信, 放到了一个信箱里, 接下来每个人从中抽取一封书信. 显然, 这样一共有 n!种拿到书信的情 ...

  6. 【2020.12.01提高组模拟】卡特兰数(catalan)

    题目 题目描述 今天,接触信息学不久的小\(A\)刚刚学习了卡特兰数. 卡特兰数的一个经典定义是,将\(n\)个数依次入栈,合法的出栈序列个数. 小\(A\)觉得这样的情况太平凡了.于是,他给出了\( ...

  7. 【2020.12.01提高组模拟】A组反思

    105,rk45 T1 赛时一开始先打了\(m=0\)的情况,也就是普通的卡特兰数,然后打了暴力,样例过了,把样例改改就不行了,原因没有保证是枚举的是合法的出栈序列 得分:\(WA\&TLE1 ...

  8. 【2020.12.02提高组模拟】A组反思

    55,rk47 T1 赛时先想了\(trie\),想到不一定是前缀,然后就放弃转为打暴力 得分:\(RE22\) 正解是只用判断\(i\)与\(i+1\)的关系,那么只有两种情况,判断一下然后\(dp ...

  9. 【2020.12.02提高组模拟】球员(player)

    题目 题目描述 老师们已经知道学生喜欢睡觉,Soaring是这项记录保持者.他只会在吃饭或玩FIFA20时才会醒来.因此,他经常做关于足球的梦,在他最近的一次梦中,他发现自己成了皇家马德里足球俱乐部的 ...

随机推荐

  1. 【无思路题目】Leetcode-1640. 能否连接形成数组

    [JAVA]参考题解 1.思路是这样子的,先用哈希表的key存下pieces的每一行的第一个元素即p[0],然后value存放相应的一维数组: 2.然后遍历arr数组,先查看每个值是否在map中,若存 ...

  2. C++ storage allocation + Dynamic memory allocation + setting limits + initializer list (1)

    1. 对象的空间在括号开始就已经分配,但是构造在定义对象的时候才会实现,若跳过(譬如goto),到括号结束析构会发生错误,编译会通不过. 2.初始化 1 struct X { int i ; floa ...

  3. SpringBoot入门最简单的一个项目示例

    使用IDEA创建一个SpringBoot项目 1.1 打开IDEA,文件-New-Project 1.2下一步,选择版本8(根据自己安装的JDK版本来选择) 1.3 下一步后点击Web,勾选Sprin ...

  4. python编写实现抽奖器

    这篇文章主要为大家详细介绍了python编写实现抽奖器,文中代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 # coding=utf-8 import sys import os ...

  5. CSS两列布局的多种方式

    两列布局(一侧固定宽度,一侧自适应),在工作中应该是经常使用到,可以说是前端基础了.这种两列布局的样式是我们在平时工作中非常常见的设计,同时也是面试中要求实现的高频题.很有必要掌握以备不时之需.这里总 ...

  6. 问题记录-CoordinatorLayout+WebView使用遇到的问题

    需求背景: 使用CoordinatorLayout+viewpager+tablayout+webview实现首页折叠效果. 使用问题: 在使用过程中首页的页面为原生/h5混合页,在原生页面正常,嵌套 ...

  7. CSS属性(CSS盒子模型)

    1.CSS盒子模型 <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset=&q ...

  8. 我要进大厂之大数据MapReduce知识点(1)

    01 我们一起学大数据 老刘今天分享的是大数据Hadoop框架中的分布式计算MapReduce模块,MapReduce知识点有很多,大家需要耐心看,用心记,这次先分享出MapReduce的第一部分.老 ...

  9. 【建议收藏】阿里P7总结的Spring注解笔记,把组件注册讲的明明白白

    环境搭建 注解的方式是通过配置类的方式来注入组件,注解注入要比XML注入的方式简单,注解注入也需要在前者的基础上,添加一个spring-context的包,也是实际开发中常用的方式. 准备所需Jar包 ...

  10. MathType怎么写分段函数?

    分段函数是数学里面特有的一种函数,它是对于自变量x的不同的取值范围,有着不同的解析式的函数.它的特点就是有一个大括号,然后有至少2个函数解析式,写这样的函数离不开专业的公式编辑器,下面就来学习具体编辑 ...