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 跳蚤王国的宰相的更多相关文章

  1. 「雅礼集训 2017 Day7」跳蚤王国的宰相(树的重心)

    题面 来源 「 雅 礼 集 训 2017 D a y 7 」 跳 蚤 王 国 的 宰 相   传 统 2000   m s 1024   M i B {\tt「雅礼集训 2017 Day7」跳蚤王国的 ...

  2. 【思维题 细节】loj#6042. 「雅礼集训 2017 Day7」跳蚤王国的宰相

    挂于±1的细节…… 题目描述 跳蚤王国爆发了一场动乱,国王在镇压动乱的同时,需要在跳蚤国地方钦定一个人来做宰相. 由于当时形势的复杂性,很多跳蚤都并不想去做一个傀儡宰相,带着宰相的帽子,最后还冒着被打 ...

  3. LOJ #6042. 「雅礼集训 2017 Day7」跳蚤王国的宰相

    我可以大喊一声这就是个思博题吗? 首先如果你能快速把握题目的意思后,就会发现题目就是让你求出每个点要成为树的重心至少要嫁接多少边 先说一个显然的结论,重心的答案为\(0\)(废话) 然后我们考虑贪心处 ...

  4. 【LOJ6042】「雅礼集训 2017 Day7」跳蚤王国的宰相(思博题)

    点此看题面 大致题意: 给你一棵树,询问对于每个点需要改变多少条边来使得它成为树中到所有点距离和最小的点. 一些初始化及想法 这是一道思博题. 首先我们要知道一个结论:对于这棵树的重心,它的答案必定为 ...

  5. ZJOI2019一轮停课刷题记录

    Preface 菜鸡HL终于狗来了他的省选停课,这次的时间很长,暂定停到一试结束,不过有机会二试的话还是可以搞到4月了 这段时间的学习就变得量大而且杂了,一般以刷薄弱的知识点和补一些新的奇怪技巧为主. ...

  6. [LOJ6029~6052]雅礼集训 2017 选做

    Link 代码可以在loj上看我的提交记录. Day 1 [LOJ6029]市场 对于一次除法操作,若区间内所有数的减少量均相同则可视作区间减法,否则暴力递归下去.显然一个线段树节点只会被暴力递归进去 ...

  7. 【HHHOJ】ZJOI2019模拟赛(十六)4.07 解题报告

    点此进入比赛 得分: \(100+100+100=300\) 排名: \(Rank\ 1\) \(Rating\): \(+13\)(\(\frac18Rated\)) 备注: 这场比赛全是做过的原题 ...

  8. loj 2955 「NOIP2018」保卫王国 - 树链剖分 - 动态规划

    题目传送门 传送门 想抄一个短一点ddp板子.然后照着Jode抄,莫名其妙多了90行和1.3k. Code /** * loj * Problem#2955 * Accepted * Time: 26 ...

  9. @loj - 2289@「THUWC 2017」在美妙的数学王国中畅游

    目录 @description@ @solution@ @accepted code@ @details@ @description@ n 个点编号 0 到 n-1,每个点有一个从 [0,1] 映射到 ...

随机推荐

  1. input 不显示输入的历史记录

    第一次在 input 输入后,下次就会自动显示输入历史记录,去掉这种默认效果的解决方案 <input name="username" type="text" ...

  2. (转)常用的三种修改mysql最大连接数的方法

    MYSQL数据库安装完成后,默认最大连接数是100,一般流量稍微大一点的论坛或网站这个连接数是远远不够的,增加默认MYSQL连接数的方法有两个 方法一:进入MYSQL安装目录 打开MYSQL配置文件 ...

  3. Python3.6爬虫+Djiago2.0+Mysql --数据爬取

    1.下载对应版本的python mysql 模块 我的是:pymssql-2.2.0.dev0-cp36-cp36m-win_amd64.whl 2.手动创建table create table gr ...

  4. tab切换 -- vue

    效果: html: // 按钮<div class="orderTab clearfix" @click="toggle()"> <div c ...

  5. dp练习集

    动态规划(DP) // 以下题目来自牛客网 删括号 f[i][j][k] 表示序列s的前i个匹配序列t的前j个,序列s删除部分左括号与右括号数量差为k的情况是否可行 答案为 f[sl][tl][0] ...

  6. Linux 静态IP配置

    静态配置文件# vim /etc/sysconfig/network-scripts/ifcfg-不同系统不一样主要几个配置TYPE=EthernetBOOTPROTO=static/noneNAME ...

  7. RaspberryPi(一)

    [1]格式化TF卡 // 注意格式 [2]烧录系统 // 烧录完成后不要点弹出的击格式化选项 [3]查找IP.修改静态IP(保持和台式机或笔记本同网段) arp -a //物理地址以B8开头 //或者 ...

  8. 将ERF格式转换成PCAP格式

    在研究网络流量分析的时候,wireshark默认采用pcap格式.对于用Endace DAG捕捉卡捕获的数据包,一般来说,都是erf格式的.一般来说,此种格式包含了更多了链路层信息.而我们采用wire ...

  9. Redis安装过程:

  10. Windows API 23 篇 WTSQuerySessionInformation

    函数原型:BOOLWINAPIWTSQuerySessionInformationW(                                                      IN ...