LOJ 6042 跳蚤王国的宰相
LOJ 6042 跳蚤王国的宰相
题意
跳蚤王国爆发了一场动乱,国王在镇压动乱的同时,需要在跳蚤国地方钦定一个人来做宰相。
由于当时形势的复杂性,很多跳蚤都并不想去做一个傀儡宰相,带着宰相的帽子,最后还冒着被打倒并杀头的危险,然而有一只跳蚤却想得与众不同最时尚。
本来他打算去教书,他已经发表了自己在学术方面的见解,获得了很多跳蚤们的赞同,但是这时听说跳蚤国要钦定宰相,他毅然打断了想去教书的想法,他觉得只要为了国家利益,自己的生死都可以不管,哪里能因为工作能给自己带来灾祸或者福分就去避开或者接近这份工作呢?所以他决定站出来接了这份工作。
然而当时国王的钦定方式很奇怪,跳蚤王国可以看作一棵树,国王认为宰相必须更好的为跳蚤服务,所以他会选择一个到所有节点距离和最小的节点,并在这个节点中钦定,如果有多个节点满足距离和最小则任选一个。
然而跳蚤国的动乱实在是太厉害了,以至于树的形态可能也会发生改变,也就是说,树上可能会有若干条边消失,如果这个情况出现的话一定会有同样数目的边出现,以保证整个结构仍然是一棵树。
现在这个跳蚤想知道每个节点中的跳蚤如果要被钦定,至少需要多少条边消失(当然也会有同样数目的边出现)。作为这只跳蚤的一名真正的粉丝,你能帮他解决这个问题吗?
数据范围\(n\le 10^6\)
解题思路
为了行文方便,我们把一个一棵树称为过重的,当且仅当它的大小大于\(\frac{n}{2}\)
一个点是重心,当且仅当它的所有子树都不是过重的。
首先,对于这棵树的重心,它的答案一定为\(0\)。
对于非重心,它的过重的子树必然只有一个,且包含重心。
对于分裂出来的子树,我们把它接到我们期望它成为重心的点上一定不劣。
我们采取这样一种贪心的策略:先分裂重心的子树,从大到小。若某一时刻重心及重心的其他子树不过重,则可以把这一整颗树分裂出来。
接下来我们来证明这种策略的正确性。
首先,当重心以及重心的其他子树的大小不过重,而重心所在的子树依然过重,那么把重心分裂出来一定最优。
因为我们考虑到重心的任意一颗子树都不过重,那么只保留一颗子树一定是合法的。
我们把重心分裂出来其实就是保留重心的一颗子树的一部分,所以一定合法。
如果此时重心过重,那么重心所在的子树必定过重
所以必然要先把重心分裂到不过重
以上。
代码实现
我们把重心的所有子树按从大到小的顺序排序,然后二分。
就做完了。
#include<bits/stdc++.h>
#define now edge[i].v
#define go(x) for(int i=head[x];i;i=edge[i].nxt)
using namespace std;
const int sz=1e6+7;
const int inf=1e9;
int n;
int tot,rt;
int u,v,cnt;
int head[sz];
int ans[sz];
int mx[sz],siz[sz];
int s[sz],pos[sz],sum[sz];
struct Edge{
int v,nxt;
}edge[sz<<1];
void make_edge(int u,int v){
edge[++cnt]=(Edge){v,head[u]};head[u]=cnt;
edge[++cnt]=(Edge){u,head[v]};head[v]=cnt;
}
bool cmp(int x,int y){
return siz[x]>siz[y];
}
void getrt(int x,int fa){
siz[x]=1;
go(x) if(now!=fa){
getrt(now,x);
mx[x]=max(mx[x],siz[now]);
siz[x]+=siz[now];
}
mx[x]=max(mx[x],n-siz[x]);
if(mx[x]<tot) tot=mx[x],rt=x;
}
void dfs(int x,int fa){
siz[x]=1;
go(x) if(now!=fa){
dfs(now,x);
siz[x]+=siz[now];
}
}
void Dfs(int x,int fa,int id){
int w=n-siz[x];
if(n-siz[id]<=n/2) ans[x]=(x!=id);
else if(w-(sum[pos[id]-1])<=n/2){
int l=0,r=pos[id]-1;
while(l<r){
int mid=(l+r)>>1;
if(w-sum[mid]<=n/2||n-siz[id]-sum[mid-1]<=n/2) r=mid;
else l=mid+1;
}
ans[x]=l;
}
else{
int l=pos[id]+1,r=tot;
while(l<r){
int mid=(l+r)>>1;
if(w-sum[mid]+siz[id]<=n/2||n-sum[mid-1]<=n/2) r=mid;
else l=mid+1;
}
ans[x]=l-1;
}
go(x) if(now!=fa) Dfs(now,x,id);
}
void solve(){
tot=0;
go(rt) s[++tot]=now;
sort(s+1,s+tot+1,cmp);
for(int i=1;i<=tot;i++){
pos[s[i]]=i;
sum[i]=sum[i-1]+siz[s[i]];
}
go(rt) Dfs(now,rt,now);
}
int main(){
scanf("%d",&n);
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
make_edge(u,v);
}
tot=inf,rt=0;
getrt(1,0);
dfs(rt,0);
solve();
for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
}
LOJ 6042 跳蚤王国的宰相的更多相关文章
- 「雅礼集训 2017 Day7」跳蚤王国的宰相(树的重心)
题面 来源 「 雅 礼 集 训 2017 D a y 7 」 跳 蚤 王 国 的 宰 相 传 统 2000 m s 1024 M i B {\tt「雅礼集训 2017 Day7」跳蚤王国的 ...
- 【思维题 细节】loj#6042. 「雅礼集训 2017 Day7」跳蚤王国的宰相
挂于±1的细节…… 题目描述 跳蚤王国爆发了一场动乱,国王在镇压动乱的同时,需要在跳蚤国地方钦定一个人来做宰相. 由于当时形势的复杂性,很多跳蚤都并不想去做一个傀儡宰相,带着宰相的帽子,最后还冒着被打 ...
- LOJ #6042. 「雅礼集训 2017 Day7」跳蚤王国的宰相
我可以大喊一声这就是个思博题吗? 首先如果你能快速把握题目的意思后,就会发现题目就是让你求出每个点要成为树的重心至少要嫁接多少边 先说一个显然的结论,重心的答案为\(0\)(废话) 然后我们考虑贪心处 ...
- 【LOJ6042】「雅礼集训 2017 Day7」跳蚤王国的宰相(思博题)
点此看题面 大致题意: 给你一棵树,询问对于每个点需要改变多少条边来使得它成为树中到所有点距离和最小的点. 一些初始化及想法 这是一道思博题. 首先我们要知道一个结论:对于这棵树的重心,它的答案必定为 ...
- ZJOI2019一轮停课刷题记录
Preface 菜鸡HL终于狗来了他的省选停课,这次的时间很长,暂定停到一试结束,不过有机会二试的话还是可以搞到4月了 这段时间的学习就变得量大而且杂了,一般以刷薄弱的知识点和补一些新的奇怪技巧为主. ...
- [LOJ6029~6052]雅礼集训 2017 选做
Link 代码可以在loj上看我的提交记录. Day 1 [LOJ6029]市场 对于一次除法操作,若区间内所有数的减少量均相同则可视作区间减法,否则暴力递归下去.显然一个线段树节点只会被暴力递归进去 ...
- 【HHHOJ】ZJOI2019模拟赛(十六)4.07 解题报告
点此进入比赛 得分: \(100+100+100=300\) 排名: \(Rank\ 1\) \(Rating\): \(+13\)(\(\frac18Rated\)) 备注: 这场比赛全是做过的原题 ...
- loj 2955 「NOIP2018」保卫王国 - 树链剖分 - 动态规划
题目传送门 传送门 想抄一个短一点ddp板子.然后照着Jode抄,莫名其妙多了90行和1.3k. Code /** * loj * Problem#2955 * Accepted * Time: 26 ...
- @loj - 2289@「THUWC 2017」在美妙的数学王国中畅游
目录 @description@ @solution@ @accepted code@ @details@ @description@ n 个点编号 0 到 n-1,每个点有一个从 [0,1] 映射到 ...
随机推荐
- <Python基础>python是如何进行内存管理的
.Python 是如何进行内存管理的?答:从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制⒈对象的引用计数机制Python 内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用 ...
- docker上安装ActiveMQ
1.查看是否已经存在镜像 docker images 2.搜索镜像 docker search activemq 3.拉取镜像 docker pull webcenter/activemq 4.构建容 ...
- 获取url指定参数值(js/vue)
function getParam(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&am ...
- data方法也是模型类的连贯操作方法之一,
data方法也是模型类的连贯操作方法之一,用于设置当前要操作的数据对象的值. 写操作 通常情况下我们都是通过create方法或者赋值的方式生成数据对象,然后写入数据库,例如: $Model = D(' ...
- 洛谷P1640 【SCOI2010】连续攻击游戏
原题传送门 题目描述 lxhgww最近迷上了一款游戏,在游戏里,他拥有很多的装备,每种装备都有2个属性,这些属性的值用[1,10000]之间的数表示.当他使用某种装备时,他只能使用该装备的某一个属性. ...
- Vue数据双向绑定(面试必备) 极简版
我又来吹牛逼了,这次我们简单说一下vue的数据双向绑定,我们这次不背题,而是要你理解这个流程,保证读完就懂,逢人能讲,面试必过,如果没做到,请再来看一遍,走起: 介绍双向数据之前,我们先解释几个名词: ...
- phpCOW机制详解
写时复制(Copy-on-Write,也缩写为COW),顾名思义,就是在写入时才真正复制一份内存进行修改. COW最早应用在*nix系统中对线程与内存使用的优化,后面广泛的被使用在各种编程语言中,如C ...
- mui.fire()用法
作用: mui.fire() 可以触发目标窗口的自定义事件 mui.fire( 目标窗口的webview , '自定义事件名' ,{参数列表}:) 目标窗口监听这个自定义事件 window.addEv ...
- StringBuffer清空
转载自:http://blog.sina.com.cn/s/blog_56fd58ab0100qfcz.html 在开发程序的时候,经常使用StringBuffer来进行字符串的拼接.如果在循环中来反 ...
- linux中断处理-顶半部(top half)和底半部(bottom half) -转
原文:http://rensanshi.blog.163.com/blog/static/21395510820136282224877/ 设备的中断会打断内核中进程的正常调度和运行,系统对更高吞吐率 ...