定義陣列
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];
}