题目链接: http://codeforces.com/problemset/problem/246/E
题意:
你现在有一棵 1 e 5 1e5 1e5 个结点的树,每个结点有一个权值。你现在有 1 e 5 1e5 1e5 个询问,每个询问会有两个值 v , k v,k v,k ,询问的是结点 v v v 的往下第 k k k 代所有结点中有多少个不同的权值。
做法:
因为每一层的结点都已经固定了,所以我们可以按照层序遍历来给每一层的结点一个位置。这样的话询问中的——结点 v v v 的往下第 k k k 代所有结点,就会变成一个区间,等于是我们在这个区间中找有多少个不同的值。这就是一个主席树的板子问题。
但是怎么去找这个区间呢,这就用到了二分,两次二分找一个左边界和一个右边界即可。
代码
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i = (int)a;i<=(int)b;i++)
#define rep_e(i,u,v) for(int i=head[u],v=to[i];~i;i=nex[i],v=to[i])
using namespace std;
typedef long long ll;
const int maxn=100005;
const int maxm=200005;
const int inf=1e9+7;
int rt[maxn*40],ls[maxn*40],rs[maxn*40],sz[maxn*40];
int a[maxn],n,q,ct,fa[maxn][25],dep[maxn],L[maxn],R[maxn];
int id[maxn],rid[maxn],ctmp,pos[maxn],d[maxn],val[maxn];
int head[maxn],to[maxm],nex[maxm],cnt;
void add(int u,int v){
to[cnt]=v;nex[cnt]=head[u];
head[u]=cnt++;
}
unordered_map<string,int > mp;
//id-i's pos£¬rid - posΪiµÄÊÇÄĸöid
void update(int &now,int las,int l,int r,int pos,int v){
now=++ct;
ls[now]=ls[las];
rs[now]=rs[las];
sz[now]=sz[las]+v;
if(l==r) return ;
int mid=(l+r)/2;
if(pos<=mid) update(ls[now],ls[las],l,mid,pos,v);
else update(rs[now],rs[las],mid+1,r,pos,v);
}
int query(int now,int las,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr){
return sz[now]-sz[las];
}
int mid=(l+r)/2,ret=0;
if(ql<=mid) ret+=query(ls[now],ls[las],l,mid,ql,qr);
if(qr>mid) ret+=query(rs[now],rs[las],mid+1,r,ql,qr);
return ret;
}
int gain(string s){
if(!mp[s]) mp[s]=++ctmp;
return mp[s];
}
void bfs(){
queue<int> Q;
Q.push(1);
int tmp=0;
while(!Q.empty()){
int v=Q.front(); Q.pop();
id[v]=++tmp;
a[tmp]=val[v];
rid[tmp]=v;
rep_e(i,v,x){
Q.push(x);
}
}
}
void dfs(int u,int dep){
d[u]=dep;
L[dep]=min(L[dep],id[u]);
R[dep]=max(R[dep],id[u]);
for(int i=head[u];~i;i=nex[i]){
fa[to[i]][0]=u;
dfs(to[i],dep+1);
}
}
void build(){
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1];
for(int i=1;i<=n;i++){
update(rt[i],rt[i-1],1,n,i,1);
if(pos[a[i]]){
int tmp=rt[i];
update(rt[i],tmp,1,n,pos[a[i]],-1);
}
pos[a[i]]=i;
}
}
int getfa(int u,int k){
for(int i=21;i>=0;i--){
if((k&(1<<i))==(1<<i)){
u=fa[u][i];
}
}
return u;
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d",&n);
rep(i,2,n+1){
string s; int ff;
cin>>s>>ff;
int ID=gain(s);
val[i]=ID; ff++;
add(ff,i);
}
n++;
bfs();
rep(i,1,n) L[i]=inf,R[i]=0;
dfs(1,1);
build();
scanf("%d",&q);
while(q--){
int p,k; scanf("%d%d",&p,&k); p++;
int aimd=d[p]+k,l,r,aiml=-1,aimr=-1;
l=L[aimd],r=R[aimd];
while(l<=r){
int mid=(l+r)/2;
int faa=getfa(rid[mid],k);
if(id[faa]>=id[p]) aiml=mid,r=mid-1;
else l=mid+1;
}
l=L[aimd],r=R[aimd];
while(l<=r){
int mid=(l+r)/2;
int faa=getfa(rid[mid],k);
if(id[faa]<=id[p]) aimr=mid,l=mid+1;
else r=mid-1;
}
if(getfa(rid[aiml],k)!=p||aiml<L[aimd]||aiml>R[aimd]||aimr<L[aimd]||aimr>R[aimd]) {
printf("0\n");
continue;
}
printf("%d\n",query(rt[aimr],0,1,n,aiml,aimr));
}
return 0;
}