http://codeforces.com/contest/686/problem/D

给出q个询问,每次要求询问以x为根的子树中,哪一个点是重心。

树的重心:求以cur为根的子树的重心,就是要找一个点,使得删除这个点后,分开来的零散的子树中,节点数的最大值最小。并且最大值最多也只是son[cur] / 2,因为最坏情况(最难分)也就是一条直线,选中间点就可以了。

例如

询问1的时候,就应该删除3,然后得到4个零散分支,2个大小是1,2个是2。

算法思路:

直观来说,应该是删除那个儿子数最多的那个节点的。 比如上图,3的儿子数最多,所以询问1就删除3了。因为,没理由再分一些节点给最大的那颗子树把,这样只会更坏。

但是却可以把最大的那颗子树分一些节点去另一边,所以优先删除最大的那颗子树的重心,然后判断是否符合要求,不符合就只能暴力往上找了。

判定条件是son[cur] > 2 * son[重心]就不行。

因为这表明son[cur] - son[重心]的值还大于son[cur] / 2

代进去就知道了son[cur] - son[重心] > son[重心],

假设son[cur] = 2 * son[重心]。那么就是剩下的节点数会大于son[cur] / 2咯。。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int maxn = + ;
int ans[maxn];
int son[maxn]; //第u个点有多少个儿子。
int fa[maxn]; //记录第i个点的爸爸是谁
struct node {
int u, v, tonext;
}e[maxn];
int first[maxn]; int num;
void add(int u, int v) {
++num;
e[num].u = u;
e[num].v = v;
e[num].tonext = first[u];
first[u] = num;
}
void dfs(int cur, int from) {
son[cur] = ; //自己一个
ans[cur] = cur; //叶子节点
int mx = -inf, pos = cur; //以这个点为子树的儿子数最多的那个pos
for (int i = first[cur]; i; i = e[i].tonext) {
dfs(e[i].v, cur);
son[cur] += son[e[i].v]; //加上儿子的节点个数
if (mx < son[e[i].v]) { //不能算自己,只能算儿子的max
mx = son[e[i].v];
pos = e[i].v; //儿子数最多的那个节点,
}
}
ans[cur] = ans[pos]; //ans[pos]已经算出来了,ans[pos]的重心
while (son[cur] > * son[ans[cur]]) {
ans[cur] = fa[ans[cur]]; //暴力往上找
}
}
void work() {
int n;
cin >> n;
int q;
cin >> q;
for (int i = ; i <= n; ++i) {
int x;
cin >> x;
add(x, i);
fa[i] = x;
}
dfs(, -);
for (int i = ; i <= q; ++i) {
int x;
cin >> x;
cout << ans[x] << endl;
}
} int main() {
#ifdef local
freopen("data.txt","r",stdin);
#endif
IOS;
work();
return ;
}

重心的定义是:

找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡

(一)
树中所有点到某个点的距离和中,到重心的距离和是最小的;如果有两个重心,那么他们的距离和一样。

(二)
把两个树通过一条边相连得到一个新的树,那么新的树的重心在连接原来两个树的重心的路径上。

(三)

把一个树添加或删除一个叶子,那么它的重心最多只移动一条边的距离。

D. Kay and Snowflake 树的重心的更多相关文章

  1. Codeforces Round #359 (Div. 2) D. Kay and Snowflake 树的重心

    题目链接: 题目 D. Kay and Snowflake time limit per test 3 seconds memory limit per test 256 megabytes inpu ...

  2. codeforces 685B Kay and Snowflake 树的重心

    分析:就是找到以每个节点为根节点的树的重心 树的重心可以看这三篇文章: 1:http://wenku.baidu.com/link?url=yc-3QD55hbCaRYEGsF2fPpXYg-iO63 ...

  3. Codeforces Round #359 (Div. 2) D. Kay and Snowflake 树DP

    D. Kay and Snowflake     After the piece of a devilish mirror hit the Kay's eye, he is no longer int ...

  4. Kay and Snowflake CodeForces - 685B (重心, 好题)

    大意:给定有根树, 求每个子树的重心 我太菜了啊, 只能想到暴力树剖, 然而这就是个B题, 感觉树剖+线段树二分还是挺难写的..... 看了题解发现重心一定在重儿子与根的树链上, 重心最多上跳n-1次 ...

  5. Kay and Snowflake CodeForces - 686D (树的重心性质)

    After the piece of a devilish mirror hit the Kay's eye, he is no longer interested in the beauty of ...

  6. B. Kay and Snowflake 解析(思維、DFS、DP、重心)

    Codeforce 685 B. Kay and Snowflake 解析(思維.DFS.DP.重心) 今天我們來看看CF685B 題目連結 題目 給你一棵樹,要求你求出每棵子樹的重心. 前言 完全不 ...

  7. CF685B Kay and Snowflake 贪心

    CF685B Kay and Snowflake 链接 CF 题目大意 给你一颗树,询问子树的重心 思路 贪心? 重心肯定是向上走的,所以直接向上跳就好了. 不优秀的时候就不要跳了 ,因为以后也不能更 ...

  8. Codeforces Round #359 (Div. 2) D - Kay and Snowflake

    D - Kay and Snowflake 题目大意:给你一棵数q个询问,每个询问给你一个顶点编号,要你求以这个点为根的子树的重心是哪个节点. 定义:一棵树的顶点数为n,将重心去掉了以后所有子树的顶点 ...

  9. Codeforces 686 D - Kay and Snowflake

    D - Kay and Snowflake 思路: 树的重心 利用重心的一个推论,树的重心必定在子树重心的连线上. 然后利用重心的性质,可知,如果有一颗子树的大小超过整棵树的大小的1/2,那么树的重心 ...

随机推荐

  1. BluetoothLE-Multi-Library 一个能够连接多台蓝牙设备的库,它可以作为client端,也可以为server端。支持主机/从机,外围设备连接。

    github地址:https://github.com/qindachang/BluetoothLE-Multi-Library BluetoothLE-Multi-Library 一个能够连接多台蓝 ...

  2. struts2 学习日记1

    struts2 简介 struts2的前身可以说是framework.strut1作为当时很流行的框架,但是有很多的不足之处,framework出生后,它带来了很好的框架,但是很多人已经习惯了stru ...

  3. linguistic相关

    Knowing a word means knowing both its sound and its meaning, while being able to use a word requires ...

  4. juery的跨域请求2

    时间过得好快,又被拉回js战场时, 跨域问题这个伤疤又开疼了. 好在,有jquery帮忙,跨域问题似乎没那么难缠了.这次也借此机会对跨域问题来给刨根问底,结合实际的开发项目,查阅了相关资料,算是解决了 ...

  5. maven的常用构建命令

    mvn clean:删除项目根目录中的target目录

  6. C++ 两款静态检查工具

    pclint(收费) http://www.gimpel.com/html/pcl.htmpc-lint是资格最老,最强力的代码检查工具,但是是收费软件,并且配置起来有一点点麻烦. ccpchecke ...

  7. 【linux+C】神器 vim + 指针相关客串

    前篇回顾 上篇介绍了linux下C编程基本环境配置以及相关工具使用选择. 不过10个大牛9个用vim,那么咱们就来玩vim.linux下玩c就别依靠图形界面.好吧告别Ide,命令行才是c的王道. 本篇 ...

  8. bzoj4066

    KD-tree 强制在线就不能愉快的做这道题了. 我们用KD-tree维护平面上的点,这样建出来的树高大概是log,复杂度过得去,但是插入过多会使树深很深,这样就能卡死,那么我们每个10000次插入就 ...

  9. 使用 Git 命令去管理项目的版本控制(一)

    参考资料:参考  参考 声明本文是作者原创,是自己的学习笔记,仅供学习参考. 在 10.11.2Mac系统中,要显示隐藏的文件夹使用命令行: defaults write com.apple.find ...

  10. Ubuntu 下编译Android 源代码

    1.配置JDK 1.6 或者1.7(看情况配置,有的Android版本不能在1.7下运行) 2.配置环境:终端:(CTRL+ALT+T) $ sudo apt-get install git gnup ...