思路:
1.询问一个节点的共有多少个不同的名字,可以用
类型的
数组来存子树某个深度某个名字出现的次数,
来记录子树某个深度有多少个不同名字的节点
2.将每次查询用容器存储,方便离线操作
3.题目给的是森林,需要存每颗树的根节点
复杂度:
MyCode:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+7,maxm=1e5+7;
typedef long long ll;
inline ll read(){
ll s = 0, w = 1; char ch = getchar();
while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); }
while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
return s * w;
}
int head[maxn],Next[maxm],to[maxm],tot;
void add(int x,int y) {
to[++tot]=y;
Next[tot]=head[x];
head[x]=tot;
}
int size[maxn],son[maxn],dep[maxn];
int ans[maxn],sum[maxn];
bool vis[maxn];
int que[maxn];
string name[maxn];
map<string,int>cnt[maxn];
#define x first
#define y second
vector<pair<int,int> >query[maxn];
void dfs1(int x,int f) {
size[x]=1;
dep[x]=dep[f]+1;
for(int i=head[x],v;i;i=Next[i]) {
v=to[i];
dfs1(v,x);
size[x]+=size[v];
if(size[son[x]]<size[v]) son[x]=v;
}
}
void calc(int x) {
if(!cnt[dep[x]][name[x]]) sum[dep[x]]+=1;
cnt[dep[x]][name[x]]+=1;
for(int i=head[x],v;i;i=Next[i]) {
v=to[i];
if(vis[v]) continue;
calc(v);
}
}
void delet(int x) {
cnt[dep[x]][name[x]]-=1;
if(!cnt[dep[x]][name[x]]) sum[dep[x]]-=1;
for(int i=head[x],v;i;i=Next[i]) {
v=to[i];
delet(v);
}
}
void dfs2(int x,bool opt) {
for(int i=head[x],v;i;i=Next[i]) {
v=to[i];
if(son[x]==v) continue;
dfs2(v,false);
}
if(son[x]) {
dfs2(son[x],true);
vis[son[x]]=true;
}
calc(x);
int size=query[x].size();
if(size) {
for(int i=0;i<size;++i)
ans[query[x][i].x]=sum[query[x][i].y];
}
if(son[x]) vis[son[x]]=false;
if(!opt) delet(x);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,m,top=0;
cin>>n;
for(int i=1,u;i<=n;++i) {
cin>>name[i]>>u;
if(u) add(u,i);
else que[++top]=i;
}
for(int i=1;i<=top;++i) dfs1(que[i],0);
cin>>m;
for(int i=1,a,k,tmp;i<=m;++i) {
cin>>a>>k;
query[a].push_back(make_pair(i,dep[a]+k));
}
for(int i=1;i<=top;++i) dfs2(que[i],false);
for(int i=1;i<=m;++i) cout<<ans[i]<<' ';
return 0;
} 
京公网安备 11010502036488号