長鏈剖分模板

x_yin發表於2024-07-13

定義陣列

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];
 } 

相關文章