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. springcloud Finchley 版本hystrix 和 hystrix Dashboard

    hystrix的断路功能 引用上个项目,创建新的model ,cloud-hystrix pom.xml <?xml version="1.0" encoding=" ...

  2. (转)Nginx+Php-fpm运行原理详解

    一.代理与反向代理 现实生活中的例子 1.正向代理:访问google.com 如上图,因为google被墙,我们需要vpn翻墙才能访问google.com. vpn对于“我们”来说,是可以感知到的(我 ...

  3. Python全栈开发:生成随机数

    #!/usr/bin/env python # -*- coding;utf-8 -*- import random def foo(args): """ :param ...

  4. vue中使用动画vue-particles实现背景粒子酷炫效果

    先来看我做的效果 我这个是用的背景色加上这个粒子效果实现的demo 平时我们做项目的话会添加背景图片这些,可能更加好看 看我的实现步骤 cnpm install -g vue-cli vue init ...

  5. html---三列布局

    三列布局 1一 1.两边固定 当中自适应 2.当中列要完整显示 3.当中列要优先加载 <!DOCTYPE html> <html> <head> <meta ...

  6. php访问其他网站接口

    使用函数:  file_get_contents($url); 传入接口url及其参数:如 $url="http://192.168.1.1/test.jsp?id=1&type=2 ...

  7. C++ 标准文件的写入读出(ifstream,ofstream)

    ttp://blog.csdn.net/a125930123/article/details/53542261     注: "<<", 插入器,向流输入数据     ...

  8. 小程序关闭时暂停webview里的音乐

    document.addEventListener("visibilitychange", () => {  if(document.hidden) {     // 页面被 ...

  9. nginx 解决问题

  10. C++ 字符串、string、char *、char[]、const char*的转换和区别

    1.字符串 字符串本质就是一串字符,在C++中大家想到字符串往往第一反应是std::string(后面简称string) 字符串得从C语言说起,string其实是个类,C语言是没有class的,所以C ...