Kay and Snowflake CodeForces - 686D

题意:给一棵有根树,有很多查询(100000级别的),查询是求以任意一点为根的子树的任意重心。

方法很多,但是我一个都不会

重心几个定义/性质:

1.从树中去掉某点以及和该点相连的所有边后,整棵树变为许多"块"。去掉任意一个重心(相比于去掉其他点)可以使得生成的各个"块"的节点数的最大值最少。

类似的一个:对于一棵树n个节点的无根树,找到一个点,使得把树变成以该点为根的有根树时,最大子树的结点数最小。

2.

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

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

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

3.(就是题面所讲的)从树中去掉某点以及和该点相连的所有边后,整棵树变为许多"块"。

去掉任意一个重心后,生成的各个"块"的节点数的最大值一定小于等于原树的节点数除以2。

4.以一棵树的重心为根的子树的节点个数,一定大于等于该树节点总数的一半。(因为不然的话把它去掉那么它的上面产生的那个连通块内部节点个数一定大于总节点数的一半,不符合性质3)

5.一棵树一定存在重心。

6.在一棵树的所有子树中,找到某一子树,使得其节点数恰好大于等于原树节点总数一半(也就是满足"节点数大于等于原树节点总数一半"这个条件的子树中节点数最小的子树),那么该子树的根一定是一个重心。

(如果该节点不是重心,也就是把它去掉后产生的连通块中至少有一个节点个数大于原树节点个数的一半。

显然这个连通块不是它上面产生的连通块,因为"(该子树)节点数大于等于原树节点总数一半",也就是它上面产生的连通块节点数一定小于原树节点总数一半。

也不可能是下面的连通块,因为它是满足"节点数大于等于原树节点总数一半"这个条件的子树中节点数最小的子树,任何节点数小于它的子树的节点数都小于原树节点总数一半,而以其子节点为根的子树的节点数一定小于以其为根的子树。

这样就产生了矛盾,因此得证

http://codeforces.com/blog/entry/45558

关于启发式合并:

http://codeforces.com/blog/entry/21827中E的题解。

合并两个答案的集合(可以为set,手写平衡树等)时,始终把size小的合并到size大的上面(相等size则任意)。

那么对于某一类问题,考虑某一个元素,会发现每次它被从一个集合合并到另一个集合时,它所在集合size至少扩大到了原来的二倍。如果最终答案集合的size是n,有n个元素,那么合并总次数就不会超过n log n级别。

方法:

1.

在某有根树中,如果(以根节点的某一子节点v为根的子树)是(以根节点的任一子节点为根的所有子树)中节点数量最多的,那么称v为该有根树根节点的最重子节点。

可以发现,一棵有根树的重心,一定在根节点到(以其最重子节点为根的子树)的重心的路径上。(根据性质1感性理解吧...)

问题:怎么证?

因此,先预处理出以任意节点为根的子树的节点数。对于某一节点,可以找到最重子节点,然后暴力从对应子树的重心往上跳枚举新重心。根据性质3,可以直接判断一个节点是不是某子树的重心,不需要通过比较。每条边最多被跳一次,边数=点数-1,因此复杂度O(n)。

2.

利用性质4、5、6以及启发式合并思想,dfs每个点,每个点返回一个包含其中所有子树size和编号的set。这样元素被加入set次数不超过n log n级别,每次加入复杂度为log n,总复杂度O(n log^2 n)。

http://codeforces.com/blog/entry/21827==>600E - Lomsat gelral  "merge sets" idea

 #include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
typedef pair<int,int> P;
struct E
{
int to,nxt;
}e[];
int f1[],ne,ans[],n,q;
set<P> dfs(int u,int fa)
//返回该子树中各个子树的size组成的集合
//P(size,编号)
{
set<P> tmp,t;
for(int k=f1[u];k;k=e[k].nxt)
if(e[k].to!=fa)
{
t=dfs(e[k].to,u);
if(t.size()>tmp.size()) swap(t,tmp);
tmp.merge(t);
}
int sz=tmp.size()+;
tmp.emplace(sz,u);
ans[u]=tmp.lower_bound(P((sz+)/,))->second;
return tmp;
}
int main()
{
int i,t;
scanf("%d%d",&n,&q);
for(i=;i<=n;i++)
{
scanf("%d",&t);
e[++ne].to=t;e[ne].nxt=f1[i];f1[i]=ne;
e[++ne].to=i;e[ne].nxt=f1[t];f1[t]=ne;
}
dfs(,);
while(q--)
{
scanf("%d",&t);
printf("%d\n",ans[t]);
}
return ;
}

Kay and Snowflake CodeForces - 686D的更多相关文章

  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 ...

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

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

  3. codeforces 686D D. Kay and Snowflake(dfs)

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

  4. Codeforces Round #359 (Div. 1) B. Kay and Snowflake dfs

    B. Kay and Snowflake 题目连接: http://www.codeforces.com/contest/685/problem/B Description After the pie ...

  5. 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 ...

  6. 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 ...

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

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

  8. Codeforces 686 D - Kay and Snowflake

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

  9. CF685B Kay and Snowflake 贪心

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

随机推荐

  1. ios开发 MPMoviePlayerController 视频播放器

    项目中用到视频播放功能, 写点视频基础部分 MPMoviePlayerController是通过MediaPlayer.frame引入的,可用于播放在iOS支持的所有格式的视频,用起来很简单!!! M ...

  2. Windows和linux双系统——改动默认启动顺序

    电脑上装了Windows 7和Ubantu双系统,因为Linux系统用的次数比較少而且还是默认的启动项对此非常不能容忍,因此得改动Windows为默认的启动项. 因为电脑上的系统引导程序是GRUB,因 ...

  3. ZOJ 2706 Thermal Death of the Universe (线段树)

    题目链接:ZOJ 2706 Thermal Death of the Universe (线段树) 题意:n个数.m个操作. 每一个操作(a,b)表示(a,b)全部值更新为这个区间的平均数:1.当前的 ...

  4. LeetCode 168 Excel Sheet Column Title(Excel的列向表标题)

    翻译 给定一个正整数,返回它作为出如今Excel表中的正确列向标题. 比如: 1 -> A 2 -> B 3 -> C ... 26 -> Z 27 -> AA 28 - ...

  5. fedora下安装xdot和objgraph

    前提:安装好了python 1.先下载xdot-0.6.tar.gz和objgraph-1.8.0-py27-none-any.whl,你也可以在官网上下载其他版本. 2.下载完后,解压. 3.打开终 ...

  6. 【C#】无损转换Image为Icon 【C#】组件发布:MessageTip,轻快型消息提示窗 【C#】给无窗口的进程发送消息 【手记】WebBrowser响应页面中的blank开新窗口及window.close关闭本窗体 【手记】调用Process.EnterDebugMode引发异常:并非所有引用的特权或组都分配给呼叫方 【C#】DataRowState演变备忘

    [C#]无损转换Image为Icon 如题,市面上常见的方法是: var handle = bmp.GetHicon(); //得到图标句柄 return Icon.FromHandle(handle ...

  7. Linux——系统调用笔记1

    底层文件访问:    进程:运行中的程序,它有一些与值关联的文件描述符,有多少个文件描述符取决于系统配置情况.    当一个程序开始运行时,一般会打开三个文件描述符:        0:标准输入    ...

  8. Linux下使用inotify实现对文件的监控

    项目中,要实现用户通过网页设置參数,后台接收数据然后写串口. 网页写数据到本地文件,使用inotify监控文件的IN_MODIFY事件.当文件被改动,然后触发写串口事件. 第一个程序只把要监控的文件增 ...

  9. 超过经理收入的员工 表的自JOIN

    https://leetcode-cn.com/problems/employees-earning-more-than-their-managers/description/ The Employe ...

  10. Perl Compatible Regular Expressions

    http://www.pcre.org/ http://www.pcre.org/