长链剖分模板

定义数组

d[i] : i 节点的深度
mxt[i] : i 的子树中深度最大的点的深度
son[i] : 长链剖分的重儿子
g[i] : log2(i)
s[x][i] : (差分数组)从x往根节点跳,每次跳i个步长停留的点的权值和(最终不一定停在根节点)
up[x][k] : 从链顶 i 往上跳 k 步得到的点
down[x][k] : 从链顶 x 往下跳 k 步得到的点

预处理

void dfs1(int x)
{
	mxt[x]=d[x]=d[f[x][0]]+1;
	for (int i=he[x];i;i=ne[i])
	{
		int y=to[i];
		if (y==f[x][0]) continue;
		f[y][0]=x;
	    dfs1(y);
		if (mxt[y]>mxt[x])
		  mxt[x]=mxt[y],son[x]=y;
	}
}
void dfs2(int x,int t)
{
	top[x]=t;
	for (int i=1,fa=f[x][0];i<=sq;i++,fa=f[fa][0])
	  s[x][i]=s[fa][i]+a[x];//预处理差分数组(倒着) 
	if (x==t) //如果是链顶记录它的上下节点
	{
		for (int i=0,o=x;i<=mxt[x]-d[x];++i)
		  up[x].pb(o),o=f[o][0];//????
		for (int i=0,o=x;i<=mxt[x]-d[x];++i)
		  down[x].pb(o),o=son[o];
	 } 
	if (son[x]) dfs2(son[x],t);
	for (int i=he[x];i;i=ne[i])
	  if (to[i]!=f[x][0]&&to[i]!=son[x])
	    dfs2(to[i],to[i]); 
}
void init()
{
	g[0]=-1;
	for (int i=1;i<=n;i++)
	  g[i]=g[i>>1]+1;
	dfs1(1);dfs2(1,1);
	for (int j=1;(1<<j)<=n;j++)
	  for (int i=1;i<=n;i++)
	    f[i][j]=f[f[i][j-1]][j-1];
 } 

求k级祖先(往上跳 k 步到达的点)

int ask(int x,int k)//o(1)求k级祖先
{
	if (d[x]-k<=0) return 0;
	if (!k) return x;
	x=f[x][g[k]];k-=1<<g[k];
	k-=d[x]-d[top[x]];x=top[x];
	if (k>=0) return up[x][k];
	else return down[x][-k];
 } 
posted @ 2024-07-13 06:50  x_yin  阅读(7)  评论(0编辑  收藏  举报