首页 > 其他分享 >树的重心

树的重心

时间:2024-08-20 21:15:07浏览次数:12  
标签:子树 重心 int siz hs 节点

树的重心

性质:一个点是重心,等价于,以这个点为根,它的每个子树的大小,都不会超过整个树大小的一半(充要条件)

性质及其证明

POJ3107

模板

这题卡vector

注意判断数组越界

void dfs(int i,int fa){
	siz[i]=1;
	int tmp=0;
	for(int j=head[i];~j;j=e[j].next){
		int v=e[j].to;
		if(v!=fa){
			dfs(v,i);
			siz[i]+=siz[v];
			tmp=max(tmp,siz[v]);
		}
	}
	tmp=max(tmp,n-siz[i]);
	if(tmp<minn){
		minn=tmp;
		pos=1;
		ans[pos]=i;
	}else if(tmp==minn){
		ans[++pos]=i;
	}
}

CF359(div1)B Kay and Snowflake

给定一棵树,根为\(1\),找到所有子树的重心

性质

设当前子树的根为\(u\),子节点为\(v_i\),\(hc(u)\)表示以\(u\)为根的子树的重心

则\(hc(u)\)在路径\((u,hc(v_i))\)上

即当前子树的重心,在当前子树的子树的重心到当前子树的根的路径上

通过这个性质,这道题首先递归初始化数组,然后自下而上地,让子节点的重心向上跳,来得到父节点的重心

void dfs(int i,int fa){
	siz[i]=1;
	ans[i]=i;
	for(int j=0;j<(int)a[i].size();j++){
		int v=a[i][j];
		if(v!=fa){
			dfs(v,i);
			siz[i]+=siz[v];
			maxn[i]=max(maxn[i],siz[v]);
		}
	}
	for(int j=0;j<(int)a[i].size();j++){
		int v=a[i][j];
		if(v!=fa){
			int k=ans[v];
			while(k!=i){
				if(max(maxn[k],siz[i]-siz[k])<=siz[i]/2){
					ans[i]=k;
					break;
				}else k=f[k];
			}
		}	
	}
}

给定一棵节点数为\(n\)的树,删一条边然后加上一条边,使得该树的重心唯一(删掉的边和加上的边可以是同一条)

如果这棵树只有一个重心,就任选一边去删,然后再加回来

如果这棵树有两个重心,那么有这样的性质

这两个重心一定相邻,删掉这两点之间的边,获得的两棵子树大小相等

所以只需让这两棵树大小不相等,从其中一棵树删边,再加到另一棵树上即可

P5666

给定一棵树,求单独删除每一条边后分裂出的两棵子树的重心编号之和

换根+倍增

性质

设当前子树的根为\(u\),重子节点为\(v\),\(hc(u)\)表示以\(u\)为根的子树的重心

若\(x\)不是\(hc(u)\),则\(hc(u)\)在以\(v\)为根的子树上

即如果根不是当前子树的重心,那么当前子树的重心在重子子树上

于是定义\(hs[u][k]\)表示\(u\)节点向重子方向跳\(2^k\)步所到达的节点

\(hs[u][0]\)即为\(u\)节点的重子

对于每一条边\((u,v)\),不妨设\(u\)为父节点,\(v\)为子节点

分别处理以\(u\)为根和以\(v\)为根的两棵子树

对于\(v\)子树

直接向下倍增找到重心即可

判断重心利用性质一个点是重心,等价于,以这个点为根,它的每个子树的大小,都不会超过整个树大小的一半(充要条件)

对于\(u\)子树

首先维护\(siz[u]\)

然后考虑到\(v\)节点可能是\(u\)节点的重子,而此时两棵树已经分裂,所以要额外维护各个节点的次重子

定义\(shs[u]\)表示\(u\)节点的次重子

所以当\(v==hs[u][0]\)时,令\(hs[u][0]=shs[u]\)

另外,当前\(u\)节点的重子还有可能是\(u\)节点的父节点

定义\(f[u]\)表示\(u\)节点的父节点

如果\(siz[f[u]]>siz[hs[u][0]]\),令\(hs[u][0]=f[u]\)

由于重子的改变,所以更新\(hs\)数组

最后向下倍增找到重心即可

分别处理完以\(u\)为根和以\(v\)为根的两棵子树后

维护\(f[u]=v\),然后递归

在处理完所有\(u\)节点的子节点\(v\)后,恢复\(hs[u][0],siz[u],f[u]\)和\(hs\)数组

ps:对于存在两个重心的情况,判断倍增得到的重心的父节点是否为重心

void init(int i,int fa){
	siz[i]=1;
	for(int j=head[i];~j;j=e[j].next){
		int v=e[j].v;
		if(v==fa)continue;
		f[v]=i;
		init(v,i);
		siz[i]+=siz[v];
		if(siz[v]>siz[hs[i][0]]){
			shs[i]=hs[i][0];
			hs[i][0]=v;
		}else if(siz[v]>siz[shs[i]]){
			shs[i]=v;
		}
	}
	for(int k=1;k<=20;k++){
		hs[i][k]=hs[hs[i][k-1]][k-1];
	}
}
bool check(int i,int s){
	return max(s-siz[i],siz[hs[i][0]])<=(s/2);
}
void update(int i){
	for(int k=1;k<=20;k++){
		hs[i][k]=hs[hs[i][k-1]][k-1];
	}
}
void dfs(int i,int fa){
	int prehs=hs[i][0],presiz=siz[i];
	for(int j=head[i];~j;j=e[j].next){
		int v=e[j].v;
		if(v==fa)continue;
		
		if(v==prehs)hs[i][0]=shs[i];
		else hs[i][0]=prehs;
		if(siz[fa]>siz[hs[i][0]])hs[i][0]=fa;
		
		update(i);
		
		siz[i]=n-siz[v],f[i]=0,f[v]=0;
		
		int p=i;
		for(int k=20;~k;k--)
			if(siz[i]-siz[hs[p][k]]<=(siz[i]/2))
				p=hs[p][k];
		ans+=p+f[p]*check(f[p],siz[i]);
		
		p=v;
		for(int k=20;~k;k--)
			if(siz[v]-siz[hs[p][k]]<=(siz[v]/2))
				p=hs[p][k];
		ans+=p+f[p]*check(f[p],siz[v]);
		
		f[i]=v;
		
		dfs(v,i);
	}
	hs[i][0]=prehs,siz[i]=presiz,f[i]=fa,update(i);
}

标签:子树,重心,int,siz,hs,节点
From: https://www.cnblogs.com/wertyuio1/p/18370344

相关文章

  • 通达信心理重心战术副图指标公式源码
    {通达信心理重心战术副图指标公式源码}N:=12;{参数可以自己调整}stICKLINE(1,100,100,10,0),COLOR0099FF;STICKLINE(1,0,0,10,0),COLOR0099FF;STICKLINE(1,80,80,1.5,0),COLORYELLOW;STICKLINE(1,20,20,1.5,0),COLORYELLOW;STICKLINE(1,50,50,0.7,0),COLORWHITE;MID:=(......
  • 中心 重心
    中心重心重心 和 中心 是两个不同的概念,但在某些情况下可以互换使用。以下是它们的定义和使用场景:重心:在数学和物理学中,重心是指一个图形或物体的几何中心点,它位于所有边或面(如果有的话)的质心位置。对于三角形来说,重心是位于三条边上的中线交点。在更复杂......
  • 重心的意思是指代事、物的核心或主要部分。
    重心的意思是指代事、物的核心或主要部分。一、重心的多种释义1、在日常语言中重心通常用来指代事物的核心或主要部分,例如“工作的重心”或“问题的重心”。2、在物理上重心是指物体各部分所受重力的合力的作用点。质量分布均匀的物体(均匀物体),重心的位置只跟物体的形状有关。......
  • 重心法判断点是否在三角形内
    1)点在三角形的边上时AP=AE+AF(向量加法)设AE=v*AB,AF=u*AC; 则AP=v*AB+u*AC(二元一次方程,u,v为我们引入的变量)根据向量三点共线定理可知:u+v=1 2) 点在三角形内时AE不变, 让AF变短一些, 当用u*AC表示AF时,u的值肯定也比1)中小了,所以此时u+v<1 所以点是否在三......
  • 数学基础:三角形重心坐标插值公式的证明
    在快速Phong明暗处理(Blinn-Phong明暗处理)时,出现了三角形重心坐标插值公式,但没有给出证明.网上也鲜有证明过程,这里给出证明.问题描述:在三角形ABC中,三顶点A、B、C坐标分别为\((x_1,y_1,z_1)、(x_2,y_2,z_2)、(x_3,y_3,z_3)\).则三角形内任一点P(x,y,z)可表示为:\[\tag{1}P=\alph......
  • P5666 [CSP-S2019] 树的重心
    考虑一个结点在什么情况下会成为重心。随便钦定一个根结点。对于结点\(u\),假设割掉了其子树\(v\)中的某条边或连接\(u\)和\(v\)的边,形成了一棵大小为\(k\)的新树。令\(mx\)表示除\(v\)子树外最大的子树大小(或\(n-siz_u\))。如果\(u\)成为了重心根据定义有\(2\ti......
  • 关于三角形的四种心(外心,内心,重心,垂心)
    外心三条边垂直平分线的交点为外心。到三顶点距离相等内心三条内角平分线的交点为内心。到三条边的距离相等同时是内切圆的圆心重心三条中心的交点为重心同时是物理意义上的重心公式:\(G(x_0,y_0),x_0=\frac{x_1+x_2+x_3}{3},y_0=\frac{y_1+y_2+y_3}{3}\)垂心......
  • 树的直径、重心、中心
    树的直径、重心、中心一、树的直径我们将一棵树\(T=(V,E)\)的直径定义为$max(u,v)(u,v∈V)$,即树中所有最短路径距离的最大值即为树的直径。求法:1)树形dp定义d1为从节点u到其子树中节点距离的最大值,d2为次大值,则\(diameter=max(d1+d2)\)特点:不可输出路径,但可以处理负边......
  • [CSP-S2019] 树的重心 题解
    [CSP-S2019]树的重心因为这道题令我十分兴奋,所以来写一下做完后的思考。这道题用到了树的重心的种种性质,在写解法的时候会一一点出其用处。首先,枚举每一条边,然后各自\(O(n)\)扫一次的\(O(n^2)\)做法是简单的。那么接下来,就会出现不同的解法了:优化\(O(n)\)求解的过程......
  • 我汤姆回来了(树和图的深度优先遍历(树的重心))(10/11)
    #include<iostream>#include<cstring>usingnamespacestd;constintN=100010;constintM=N*2;//可能多次节点重复,所以开大intn;inte[M],ne[M],h[N],idx=0;boolst[N];intans=N;//记录最后最小值答案//单链表的连接,不同点就是头结点有多个voidadd(i......