E. Blood Cousins(树上启发式合并+简单倍增)

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

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

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

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

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

x s h e n [ 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) );
}

猜你喜欢

转载自blog.csdn.net/jziwjxjd/article/details/108348582