点分治

变量

  • int n\texttt{int n}:树的节点数。
  • int a[i]\texttt{int a[i]}:临时存储每个点到分治中心的链的信息。
  • int tt\texttt{int tt}aa 数组的大小。
  • int d[i]\texttt{int d[i]}:点 ii 到分治中心的链的信息,代码中以到分治中心经过的边数为例。
  • int mx[i]\texttt{int mx[i]}:以 ii 为重心时其最大子树的大小。
  • int root\texttt{int root}:此时的重心。
  • int S\texttt{int S}:此时分治区域的大小。
  • bool v[i]\texttt{bool v[i]}:标记节点 ii 是否成为过分治中心。

函数

  • void get_root(int x,int fa)\texttt{void get\_root(int x,int fa)}:求 mxxmx_x,父亲为 fafa,并用 mxxmx_x 更新 rootroot
  • void get_dis(int x,int fa)\texttt{void get\_dis(int x,int fa)}:求子树 xx 到分治中心的链的信息,xx 的父亲为 fafa
  • void calc(int x)\texttt{void calc(int x)}:求解问题。
  • void DFZ(int x)\texttt{void DFZ(int x)}:分治以 xx 为分治中心的区域。
  • void ask()\texttt{void ask()}:进行点分治。

代码

int n;
int a[N],tt,d[N],s[N],mx[N];
int root,S;
bool v[N];
void get_root(int x,int fa){
	s[x]=1;
	mx[x]=0;
	for(int i=head[x];i;i=nxt[i]){
		int y=ver[i];
		if(v[y]||y==fa)
			continue;
		get_root(y,x);
		s[x]+=s[y];
		mx[x]=max(mx[x],s[y]);
	}
	mx[x]=max(mx[x],S-s[x]);
	if(mx[x]<mx[root])
		root=x;
}
void get_dis(int x,int fa){
	a[++tt]=d[x];
	for(int i=head[x];i;i=nxt[i]){
		int y=ver[i],z=edge[i];
		if(v[y]||y==fa)
			continue;
		d[y]=d[x]+z;
		get_dis(y,x);
	}
}
void calc(int x){
	for(int i=head[x];i;i=nxt[i]){
		int y=ver[i],z=nxt[i];
		if(v[y])
			continue;
		d[y]=z;
		get_dis(y,x);
		//solve the problem
	}
}
void DFZ(int x){
	v[x]=1;
	calc(x);
	for(int i=head[x];i;i=nxt[i]){
		int y=ver[i];
		if(v[y])
			continue;
		S=s[y];
		mx[root=0]=1e9;
		get_root(y,0);
		DFZ(root);
	}
}
void ask(){
	S=n;
	mx[root=0]=1e9;
	get_root(1,0);
	DFZ(root);
}
posted @ 2022-08-28 21:03  luckydrawbox  阅读(9)  评论(0)    收藏  举报  来源