其实做法很简单,开始居然脑抽不知道怎么统计树上k级祖先…

和 自 己 有 相 同 的 k 级 祖 先 , 相 当 于 和自己有相同的k级祖先,相当于 和自己有相同的k级祖先,相当于

每 个 点 有 对 应 自 己 的 k 级 儿 子 , 可 以 把 询 问 集 中 到 点 上 ( 作 为 k 级 父 亲 ) 每个点有对应自己的k级儿子,可以把询问集中到点上(作为k级父亲) 每个点有对应自己的k级儿子,可以把询问集中到点上(作为k级父亲)

至 于 这 个 k 级 父 亲 , 倍 增 很 容 易 实 现 至于这个k级父亲,倍增很容易实现 至于这个k级父亲,倍增很容易实现

然 后 书 上 启 发 式 合 并 维 护 一 下 s h e n [ ] 数 组 然后书上启发式合并维护一下shen[]数组 然后书上启发式合并维护一下shen[]数组

代 表 当 前 子 树 深 度 是 x 的 有 s h e n [ x ] 个 代表当前子树深度是x的有shen[x]个 代表当前子树深度是x的有shen[x]个

#include <bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
struct edge{
int to,nxt;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v){ d[++cnt]=(edge){v,head[u]},head[u]=cnt; }
typedef pair<int,int>p;
vector<p>vec[maxn];
int n,m,son[maxn],siz[maxn],deep[maxn],ans[maxn][20],an[maxn];
string a[maxn];
void dfs(int u,int father,int depth)
{
siz[u]=1,deep[u]=depth,ans[u][0]=father;
int maxson=-1;
for(int i=1;i<=18;i++)
ans[u][i]=ans[ ans[u][i-1] ][i-1];
for(int i=head[u];i;i=d[i].nxt )
{
int v=d[i].to;
if( v==father ) continue;
dfs(v,u,depth+1);
siz[u]+=siz[v];
if( maxson<siz[v] ) maxson=siz[v],son[u]=v;
}
}
int nowson,shu[maxn];
int k_th(int u,int k)
{
for(int i=0;i<=18;i++)
if( ((1<<i)&k) ) u=ans[u][i];
return u;
}
void update(int u,int father,int val)
{
shu[deep[u]]+=val;
for(int i=head[u];i;i=d[i].nxt )
{
int v=d[i].to;
if( v==father||v==nowson ) continue;
update(v,u,val);
}
}
void dsu(int u,int father,bool keep)
{
for(int i=head[u];i;i=d[i].nxt )
{
int v=d[i].to;
if( v==father || v==son[u] ) continue;
dsu(v,u,0);
}
if( son[u] ) dsu(son[u],u,1),nowson=son[u];
update(u,father,1); nowson=0;
for(int i=0;i<vec[u].size();i++)
{
p v=vec[u][i];
an[v.second]=shu[v.first+deep[u]];
}
if( !keep ) update(u,father,-1);
}
int main()
{
cin >> n;
for(int i=1;i<=n;i++)
{
int x; cin >> x;
add(x,i); add(i,x);
}
dfs(0,0,1);
cin >> m;
for(int i=1;i<=m;i++)
{
int l,r,kfa; cin >> l >> r;
kfa = k_th(l,r);
if( kfa==0 ) continue;
vec[kfa].push_back( p(r,i) );
}
dsu(0,0,1);
for(int i=1;i<=m;i++) printf("%d ",max(0,an[i]-1) );
}

还 有 树 剖 的 还有树剖的 还有树剖的

#include <bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
struct edge{
int to,nxt;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v){ d[++cnt]=(edge){v,head[u]},head[u]=cnt; }
typedef pair<int,int>p;
vector<p>vec[maxn];
int n,m,son[maxn],siz[maxn],deep[maxn],an[maxn],fa[maxn];
string a[maxn];
void dfs(int u,int father,int depth)
{
siz[u]=1,deep[u]=depth,fa[u]=father;
int maxson=-1;
for(int i=head[u];i;i=d[i].nxt )
{
int v=d[i].to;
if( v==father ) continue;
dfs(v,u,depth+1);
siz[u]+=siz[v];
if( maxson<siz[v] ) maxson=siz[v],son[u]=v;
}
}
int id[maxn],num,top[maxn],rk[maxn];
void dfs2(int u,int father,int topf)
{
rk[++num]=u,top[u]=topf,id[u]=num;
if( !son[u] ) return;
dfs2(son[u],u,topf);
for(int i=head[u];i;i=d[i].nxt )
{
if( d[i].to==father||d[i].to==son[u] ) continue;
dfs2(d[i].to,u,d[i].to);
}
}
int nowson,shu[maxn];
int k_th(int u,int k)
{
while( k>deep[u]-deep[top[u]] )
{
k-=( deep[u]-deep[top[u]]+1 );
u=fa[top[u]];
}
return rk[ id[u]-k ];
}
void update(int u,int father,int val)
{
shu[deep[u]]+=val;
for(int i=head[u];i;i=d[i].nxt )
{
int v=d[i].to;
if( v==father||v==nowson ) continue;
update(v,u,val);
}
}
void dsu(int u,int father,bool keep)
{
for(int i=head[u];i;i=d[i].nxt )
{
int v=d[i].to;
if( v==father || v==son[u] ) continue;
dsu(v,u,0);
}
if( son[u] ) dsu(son[u],u,1),nowson=son[u];
update(u,father,1); nowson=0;
for(int i=0;i<vec[u].size();i++)
{
p v=vec[u][i];
an[v.second]=shu[v.first+deep[u]];
}
if( !keep ) update(u,father,-1);
}
int main()
{
//ios::sync_with_stdio(false);
cin >> n;
for(int i=1;i<=n;i++)
{
int x; cin >> x;
add(x,i); add(i,x);
}
dfs(0,0,1); dfs2(0,0,0);
cin >> m;
for(int i=1;i<=m;i++)
{
int l,r,kfa; cin >> l >> r;
if( deep[l]<=r+1 ) continue;
kfa = k_th(l,r);
vec[kfa].push_back( p(r,i) );
}
dsu(0,0,1);
for(int i=1;i<=m;i++) printf("%d ",max(0,an[i]-1) );
}