1 条题解

  • 0
    @ 2021-11-19 8:27:24

    考虑先离线,再处理答案。

    考虑一个询问与 xx 有相同 kk 级祖先的点,等于询问在 xxkk 级祖先的点的子树中与 xx 深度相同的点的个数。

    直接用线段树合并维护,一个点的权值就是深度。


    代码
    #include<bits/stdc++.h>
    #define mid (l+r>>1)
    using namespace std;
    const int N=1e5+5;
    int n,f[N][25],m,ans[N],dep[N],cnt,rt[N];
    struct segtree{int l,r,sum;}tr[N*40];
    vector<int> e[N];
    vector<pair<int,int> > que[N];
    void dfs(int x){
    	for(int i=1;i<=20;i++)f[x][i]=f[f[x][i-1]][i-1];
    	for(int y:e[x]){
    		dep[y]=dep[x]+1;
    		dfs(y);
    	}
    }
    void add(int &p,int l,int r,int x,int z){
    	if(!p)p=++cnt;
    	if(l==r){
    		tr[p].sum+=z;
    		return;
    	}
    	if(x<=mid)add(tr[p].l,l,mid,x,z);
    	else add(tr[p].r,mid+1,r,x,z);
    }
    void he(int &p,int q,int l,int r){
    	if(!p||!q){p=q+p;return;}
    	if(l==r){
    		tr[p].sum+=tr[q].sum;
    		return; 
    	}
    	he(tr[p].l,tr[q].l,l,mid);
    	he(tr[p].r,tr[q].r,mid+1,r);
    }
    int ask(int p,int l,int r,int x){
    	if(!p)return 0;
    	if(l==r)return tr[p].sum;
    	if(x<=mid)return ask(tr[p].l,l,mid,x);
    	else return ask(tr[p].r,mid+1,r,x);
    }
    int jump(int x,int y){
    	for(int i=0;i<=20;i++)if(y&(1<<i))x=f[x][i];
    	return x;
    }
    void dfs1(int x){
    	for(int y:e[x]){
    		dfs1(y);
    		he(rt[x],rt[y],1,n);
    	}
    	for(auto i:que[x])ans[i.second]=ask(rt[x],1,n,dep[x]+i.first)-1;
    	add(rt[x],1,n,dep[x],1);
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&f[i][0]);
    		if(f[i][0])e[f[i][0]].push_back(i);
    	}
    	for(int i=1;i<=n;i++)if(!f[i][0])dep[i]=1,dfs(i);
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++){
    		int x,K;
    		scanf("%d%d",&x,&K);
    		int t=jump(x,K);
    		if(t)que[t].emplace_back(K,i);
    	}
    	for(int i=1;i<=n;i++)if(!f[i][0])dfs1(i);
    	for(int i=1;i<=m;i++)printf("%d ",ans[i]);
    }
    
    • 1

    信息

    ID
    2
    时间
    2000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    4
    已通过
    3
    上传者