链接:http://codeforces.com/problemset/problem/208/E
题意: 现在有若干棵树,对于每次一询问,都有一个节点 u 和一个 k 你要求出在这棵树上与u 同为k 级兄弟的节点个数,也就是与u的k级父亲是同一个父亲的,节点个数。
思路: 对于每一个节点u和k ,如果他的深度<k 那么肯定是找不到的,答案为0 ,否则,我先找到的他的k级父亲,也就是询问这个节点有多少k级孩子。k级孩子的个数-1 ,那么如何在nlogn 的时间内找到他的k级孩子的个数。当然就是dsu on tree 的问题了。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int ,int > pii;
const int N =100010;
const int DEG=20;
struct Edge
{
int v;
int next;
}edge[N*2];
int head[N],tot;
int fa[N][21];
int deg[N];
void init()
{
memset(head,-1,sizeof(head));
tot=0;
}
void adde(int u,int v)
{
edge[++tot].v=v;
edge[tot].next=head[u];
head[u]=tot;
}
void bfs(int root)
{
queue< int >que;
deg[root]=0;
que.push(root);
while(!que.empty()){
int tmp=que.front();
que.pop();
for(int i=1;i<DEG;i++)
fa[tmp][i]=fa[fa[tmp][i-1]][i-1];
for(int i=head[tmp];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(v==fa[tmp][0] ) continue;
deg[v]=deg[tmp]+1;
fa[v][0]=tmp;
que.push(v);
}
}
}
int find_kfa(int x,int k)
{
for(int i=0;i<DEG;i++){
if((k>>i)&1) x=fa[x][i];
}
return x;
}
int n,m;
int sz[N];
bool big[N];
int ans[N];
int rt[N];
int rttot;
vector< pii >ve[N];
struct node
{
int u;
int k;
int ans;
}xun[N];
void dfs(int u)
{
sz[u]=1;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
dfs(v);
sz[u]+=sz[v];
}
return ;
}
void add(int u,int flag)
{
if(flag==1){
ans[deg[u]]++;
}
else ans[deg[u]]--;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(big[v]) continue;
add(v,flag);
}
}
void dfs1(int u,int keep)
{
int mx=-1,bigc=-1;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(sz[v]>mx){
mx=sz[v];
bigc=v;
}
}
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(v==bigc) continue;
dfs1(v,0);
}
if(bigc!=-1){
dfs1(bigc,1);
big[bigc]=1;
}
add(u,1);
/*cout<<"**** u "<<u<<endl;
for(int i=0;i<=n;i++){
cout<<ans[i]<<" ";
}
cout<<endl;
*/
for(int i=0;i<ve[u].size();i++){
int k=ve[u][i].first; int id=ve[u][i].second;
if(k+deg[u]<=n) xun[id].ans=max(ans[deg[u]+k]-1,0);
}
if(bigc!=-1){
big[bigc]=0;
}
if(keep==0) add(u,-1);
}
int main()
{
scanf("%d",&n);
init();
int x;
for(int i=1;i<=n;i++){
scanf("%d",&x);
if(x==0){
rt[++rttot]=i;
}
else{
adde(x,i);
}
}
for(int i=1;i<=rttot;i++){
bfs(rt[i]);
}
scanf("%d",&m);
int u,k;
for(int i=1;i<=m;i++){
scanf("%d %d",&xun[i].u,&xun[i].k);
u=xun[i].u; k=xun[i].k;
if(deg[u]<k){
xun[i].ans=0;
continue;
}
int kfa=find_kfa(u,k);
//cout<<" kfa "<<kfa<<endl;
ve[kfa].push_back(pii(k,i));
}
for(int i=1;i<=rttot;i++){
dfs(rt[i]);
dfs1(rt[i],0);
}
for(int i=1;i<=m;i++){
printf("%d ",xun[i].ans);
}
return 0;
}
/*
*/