长链剖分模板
定义数组
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];
}