CF246E Blood Cousins Return 题解
前言
感谢 @zhengdongwen 大佬给予我的非常关键的帮助(拜谢)。
分析
考虑莫队。
对于这道题,我们可以想到 DFS 序。定义
这是一个区间问题,直接用莫队维护。定义
注:我们需要使用类似于 map 的容器存放
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int,int>
#define x first
#define y second
#define re register
#define il inline
const int N=1e6+10;
int n,q;
string name[N];
//dfs序 ↓
int ne[N],e[N],h[N],idx;
int fi[N],dfsx[N],cnt,dep[N];//fi[i]:节点i在dfs序中出现的下标
int siz[N];
il void add(int a,int b){
ne[++idx]=h[a],e[idx]=b,h[a]=idx;
return ;
}
il void dfs(int now,int fa){
dep[now]=dep[fa]+1,dfsx[++cnt]=now,fi[now]=cnt;
siz[now]=1;
for(int i=h[now];i;i=ne[i]){
int j=e[i];if(j==fa) continue;
dfs(j,now),siz[now]+=siz[j];
}
return ;
}
//dfs序 ↑
//输入 ↓
struct node{
int l,r,dep,id;//dep存放dep[x]+y
}Q[N];
il void read(){
scanf("%lld",&n);
int idex=0;
for(int i=1;i<=n;i++){
int x; cin>>name[i];scanf("%lld",&x);
add(x,i),add(i,x);
}
dfs(0,-1); scanf("%lld",&q);
for(int i=1;i<=q;i++){
int x,y;scanf("%lld%lld",&x,&y);
Q[i]={fi[x],fi[x]+siz[x]-1,dep[x]+y,i};
}
return ;
}
//输入 ↑
//莫队 ↓
int len,ANS[N];
int many[N];
unordered_map<int,unordered_map<string,int>> h_m;
bool cmp(node a,node b){
if(a.l/len!=b.l/len) return a.l<b.l;
if((a.l/len)&1) return a.r<b.r;
return a.r>b.r;
}
void add1(int x){
h_m[dep[x]][name[x]]++;
if(h_m[dep[x]][name[x]]==1)
many[dep[x]]++;
return ;
}
void del1(int x){
h_m[dep[x]][name[x]]--;
if(h_m[dep[x]][name[x]]==0)
many[dep[x]]--;
return ;
}
void solve(){
len=sqrt(n),sort(Q+1,Q+q+1,cmp);
int l=1,r=0;
for(int i=1;i<=q;i++){
while(l>Q[i].l) add1(dfsx[--l]);
while(r<Q[i].r) add1(dfsx[++r]);
while(l<Q[i].l) del1(dfsx[l++]);
while(r>Q[i].r) del1(dfsx[r--]);
ANS[Q[i].id]=many[Q[i].dep];
}
return ;
}
//莫队 ↑
void print(){
for(int i=1;i<=q;i++)
printf("%lld\n",ANS[i]);
return ;
}
signed main(){
read(),solve(),print();return 0;
}