CodeForces - 246E Blood Cousins Return(树上启发式合并)

本文介绍了一种解决家谱树深度查询问题的算法,通过维护节点深度和使用set进行去重,统计以任意节点为根的子树中,特定深度的节点名字种类数。文章详细解析了代码实现,包括深度优先搜索、子树统计和查询处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:点击查看

题目大意:给出一棵家谱树,定义从 u 点向上走 k 步到达的节点为 u 的 k-ancestor,每个节点有名字,名字不唯一。多次查询,给出 u 和 k,问以 u 为根节点的子树下有多少个深度为 dep[u] + k 的节点(dep[u] 为节点 u 的深度)。

题目分析:有了之前那道题目的铺垫后:CodeForces - 208E Blood Cousins,这道题目机会就是来白给的,与前一道题目不同的是,这个题目是需要统计以u为根节点的子树中,相对深度为k的子结点中,有多少种名字,注意这里,是多少种而不是多少个,既然是需要去重,那么直接上set和string配合使用就好了,将前一个题目中的cnt替换为set就大功告成了

有个细节需要注意一下,题目中给出的u和k,可能会无解,我们有两种方法,一种是在dfs维护深度时顺便维护一下max_deep,用来限制范围,超过范围的直接将答案置零即可,或者是一开始就将set数组开大点,大上个两倍就够了

代码:

#include<iostream>
#include<cstdio> 
#include<string>
#include<ctime>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<unordered_map>
using namespace std;

typedef long long LL;

const int inf=0x3f3f3f3f;

const int N=1e5+100;

string name[N];

int deep[N],son[N],num[N],ans[N],limit,max_deep;

bool vis[N];

set<string>st[N<<1];

vector<int>node[N];

vector<pair<int,int>>Q[N];//<id,deep>

void dfs_son(int u,int dep)
{
	max_deep=max(dep,max_deep);
	son[u]=-1;
	num[u]=1;
	deep[u]=dep;
	for(auto v:node[u])
	{
		dfs_son(v,dep+1);
		num[u]+=num[v];
		if(son[u]==-1||num[son[u]]<num[v])
			son[u]=v;
	}
}

void cal(int u,int val)
{
	if(val==1)
		st[deep[u]].insert(name[u]);
	else
		st[deep[u]].erase(name[u]);
	for(auto v:node[u])
	{
		if(vis[v])
			continue;
		cal(v,val);
	}
}

void dfs(int u,int keep)
{
	for(auto v:node[u])
	{
		if(v==son[u])
			continue;
		dfs(v,0);
	}
	if(son[u]!=-1)
	{
		dfs(son[u],1);
		vis[son[u]]=true;
	}
	cal(u,1);
	for(auto i:Q[u])
	{
		int id=i.first;
		int d=i.second;
		ans[id]=st[d].size();
	}
	if(son[u]!=-1)
		vis[son[u]]=false;
	if(!keep)
		cal(u,-1);
}

int main()
{
//	freopen("input.txt","r",stdin);
//	ios::sync_with_stdio(false);
	int n,m;
	scanf("%d",&n);
	limit=log2(n)+1;
	for(int i=1;i<=n;i++)
	{
		cin>>name[i];
		int fa;
		scanf("%d",&fa);
		node[fa].push_back(i);
	}
	dfs_son(0,0);
	scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		int u,d;
		scanf("%d%d",&u,&d);
		Q[u].push_back(make_pair(i,deep[u]+d));
	}
	dfs(0,1);
	for(int i=1;i<=m;i++)
		printf("%d\n",ans[i]);
	
	
	
	
	
	
	
	
	
	
	return 0;
}