zoukankan      html  css  js  c++  java
  • CF685B Solution

    题目链接

    题解

    若树的重心为根节点,所有子树大小均小于树大小的\(\frac{1}{2}\)。易得,当树的重心并非根节点时,其一定在树的最大子树中。设最大子树重心为\(cen\)\(cen\)的子树一定小于最大子树的\(\frac{1}{2}\),也小于整棵树的\(\frac{1}{2}\)。因此我们只需不断上移\(cen\),因为树的重心一定存在,所以第一个满足全树除\(cen\)的子树外的部分也小于全树的\(\frac{1}{2}\)的节点一定为重心。

    上述过程可用递归实现,记录所有节点子树的重心后离线回答询问即可。因为所有\(cen\)只升不降,时间复杂度约为\(O(n)\)

    AC代码

    #include<iostream>
    using namespace std;
    const int N=3e5+10;
    int fst[N],nxt[N*2],v[N*2],cnt;
    int cen[N],siz[N],fa[N];//cen[i]:节点i子树的重心,siz[i]:节点i子树的大小
    void add(int x,int y)
    {
    	v[++cnt]=y;
    	nxt[cnt]=fst[x]; fst[x]=cnt;
    } 
    void dfs(int x)
    {
    	siz[x]=1,cen[x]=x;//初始x子树的重心为x
    	for(int i=fst[x];i;i=nxt[i])
    	{
    		int y=v[i]; 
    		if(y!=fa[x]) 
    		{
    			fa[y]=x; dfs(y); 
    			siz[x]+=siz[y];
    		}
    	}
    	for(int i=fst[x];i;i=nxt[i])
    	{
    		int y=v[i];
    		if(y!=fa[x] && siz[y]*2>siz[x]) cen[x]=cen[y];//记录大于全树一半子树的重心
    	}
    	while((siz[x]-siz[cen[x]])*2>siz[x]) cen[x]=fa[cen[x]];//上移
    }
    int main()
    {
    	int n,q,x;
    	scanf("%d%d",&n,&q);
    	for(int i=2;i<=n;i++)
    	{
    		scanf("%d",&x);
    		add(x,i),add(i,x);
    	}
    	dfs(1);
    	while(q--) {scanf("%d",&x); printf("%d\n",cen[x]);}
    	return 0;
    }
    
  • 相关阅读:
    “访问”美术馆
    加分二叉树
    有线电视网
    二叉苹果树
    鬼子进村
    遍历问题
    最大子树和
    FBI树
    求前序遍历
    JS如何实现点击页面内任意的链接均加参数跳转?
  • 原文地址:https://www.cnblogs.com/violetholmes/p/14388364.html
Copyright © 2011-2022 走看看