树上 K 级祖先 + 分块
  • 板块CF208E Blood Cousins
  • 楼主sLMxf
  • 当前回复11
  • 已保存回复11
  • 发布时间2024/10/10 19:44
  • 上次更新2024/10/10 21:38:45
查看原帖
树上 K 级祖先 + 分块
752953
sLMxf楼主2024/10/10 19:44

rt,WA#8.

思路就是先拍成序列,然后分块维护每一块值为 kk 的数的数的个数。代码如下:

#include<bits/stdc++.h>
using namespace std;
int dep[100005];
int dfn[100005];
int tot=-1,n,r[100005];
int num[100005][320]={0},l[320],id[100005];
vector<int> G[100005];
int fa[100005][35];
int Log2[100005];
void logg()
{
	Log2[0]=Log2[1]=0;
	for(int i=2;i<=100002;i++)
		Log2[i]=Log2[i/2]+1;
}
int KZX(int x,int k)
{
    int f=0;
    while(k)
    {
        if(k%2) x=fa[x][f];
        f++,k/=2;
	}
	return x;
}
void dfs(int x)
{
	dfn[x]=++tot;
	dep[x]=dep[fa[x][0]]+1;
	for(int i=1;i<=Log2[dep[x]];i++)
		fa[x][i]=fa[fa[x][i-1]][i-1];
	for(int i=0;i<G[x].size();i++)
		dfs(G[x][i]);
	r[x]=tot;
}
void ycl()
{
	int kc=sqrt(n);
	tot=0;
	for(int i=1;i<=n;i++)
	{
		id[i]=(i-1)/kc+1;
		if(id[i]!=id[i-1]) l[++tot]=i;
	}
	l[1+tot]=n+1;
	for(int i=1;i<=n;i++)
		num[dep[i]][id[i]]++;
}
int update(int L,int R,int k)
{
	int idl=id[L],idr=id[R],ans=0;
	if(idl==idr)
	{
		for(int i=L;i<=R;i++) ans+=(dep[i]==k);
		return ans-1;
	}
	else
	{
		for(int i=L;i<l[idl+1];i++) ans+=(dep[i]==k);
		for(int i=l[idr];i<=R;i++) ans+=(dep[i]==k);
		for(int i=idl+1;i<idr;i++) ans+=num[k][i];
		return ans-1;
	}
}
void solve()
{
	int v,p;
	cin>>v>>p;
	int vp=KZX(v,p);
	if(vp==0) cout<<"0 ";
	else cout<<max(update(dfn[vp],r[vp],dep[v]),0)<<' ';
}
signed main()
{
	logg();
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>fa[i][0];
		G[fa[i][0]].push_back(i);
	}
	dep[0]=-1;
	dfs(0);
	ycl();
	int q;
	for(cin>>q;q--;solve());
	return 0;
}
2024/10/10 19:44
加载中...