D. Kay and Snowflake 树的重心
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 树的重心的更多相关文章
- 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 ...
- codeforces 685B Kay and Snowflake 树的重心
分析:就是找到以每个节点为根节点的树的重心 树的重心可以看这三篇文章: 1:http://wenku.baidu.com/link?url=yc-3QD55hbCaRYEGsF2fPpXYg-iO63 ...
- 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 ...
- Kay and Snowflake CodeForces - 685B (重心, 好题)
大意:给定有根树, 求每个子树的重心 我太菜了啊, 只能想到暴力树剖, 然而这就是个B题, 感觉树剖+线段树二分还是挺难写的..... 看了题解发现重心一定在重儿子与根的树链上, 重心最多上跳n-1次 ...
- 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 ...
- B. Kay and Snowflake 解析(思維、DFS、DP、重心)
Codeforce 685 B. Kay and Snowflake 解析(思維.DFS.DP.重心) 今天我們來看看CF685B 題目連結 題目 給你一棵樹,要求你求出每棵子樹的重心. 前言 完全不 ...
- CF685B Kay and Snowflake 贪心
CF685B Kay and Snowflake 链接 CF 题目大意 给你一颗树,询问子树的重心 思路 贪心? 重心肯定是向上走的,所以直接向上跳就好了. 不优秀的时候就不要跳了 ,因为以后也不能更 ...
- Codeforces Round #359 (Div. 2) D - Kay and Snowflake
D - Kay and Snowflake 题目大意:给你一棵数q个询问,每个询问给你一个顶点编号,要你求以这个点为根的子树的重心是哪个节点. 定义:一棵树的顶点数为n,将重心去掉了以后所有子树的顶点 ...
- Codeforces 686 D - Kay and Snowflake
D - Kay and Snowflake 思路: 树的重心 利用重心的一个推论,树的重心必定在子树重心的连线上. 然后利用重心的性质,可知,如果有一颗子树的大小超过整棵树的大小的1/2,那么树的重心 ...
随机推荐
- Loadrunner进行性能测试的步骤
Loadrunner 11是一款免费的性能测试工具,他包含三个大模块 •使用VuGen:创建脚本•运用Controller:设置方案•查看Analysis:分析测试结果 结合软件测试的流程可以知道使用 ...
- poj图论解题报告索引
最短路径: poj1125 - Stockbroker Grapevine(多源最短路径,floyd) poj1502 - MPI Maelstrom(单源最短路径,dijkstra,bellman- ...
- nyoj 269 VF
VF 时间限制:1000 ms | 内存限制:65535 KB 链接:NYOJ269 原创在:点击打开链接 题意:1-1000000000之间,各位数字之和等于给定s的数的个数. 每行给出一个数s ...
- BZOJ_3123_[Sdoi2013]森林_主席树+启发式合并
BZOJ_3123_[Sdoi2013]森林_主席树+启发式合并 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20 ...
- java.lang.NoSuchMethodException: com.sun.proxy.$Proxy
删掉了@Transactional注解,结果成功了 是这个注解造成的. 是ssh2的整合强制我们使用分层架构.
- js 弹出QQ对话框
首先打开下面链接,开通QQ推广. http://shang.qq.com/v3/index.html 然后在页面代码中写入 <a target="_blank" href=& ...
- Lsyncd搭建同步镜像-用Lsyncd实现本地和远程服务器之间实时同步
Lysncd即Live Syncing Daemon,它是开源的数据实时同步工具(后台进程),基于inotify和rsync. lsyncd会密切监测本地服务器上的参照目录,当发现目录下有文件或目录变 ...
- Linux Ctrl+Z的使用方法
假设你发现前台运行的一个程序需要很长的时间,但是需要干其他的事情,你就可以用 Ctrl-Z ,终止这个程序,然后可以看到系统提示: [1]+ Stopped /root/bin/rsync.sh 然后 ...
- Andriod开发 --插件安装、环境配置、问题集锦
1.用Eclipse搭建Android开发环境和创建第一个Android项目(Windows平台) 链接阅读http://www.cnblogs.com/allenzheng/archive/2012 ...
- Count Subsets
题意: 给一集合 $S = \{ 1,2, ... , n \} $,取两个S的子集 A和B,使得A不是B的子集,且B不是A的子集. 解法: 1.牛顿展开 我们采用容斥,显然有 $$ans(n) = ...