CF208E Blood Cousins

洛咕

题意:给你一片森林,每次询问一个点与多少个点拥有共同的\(K\)级祖先.\(n,m<=100000.\)

分析:先不管森林不森林的(森林就当做多棵独立的树来处理就好了,反正产生的贡献相互不影响),在一棵树上,我们要维护每个点有多少个点的深度与之相同,空间是开不下的.所以我们需要稍微转化一下,维护每个点的深度为\(K\)的儿子有多少个.所以我们先通过\(LCA\)找到节点\(x\)\(K\)级祖先\(y\),然后把\((y,dep[u])\)当做一组询问,表示要查询\(y\)的子树中深度为\(dep[u]\)的儿子的数量.

#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=1e5+5;
int n,m;
int f[N][20],visit[N],sum[N],ans[N];
int dep[N],root[N],size[N],son[N];
int tot,head[N],nxt[N],to[N],Head[N];
inline void add(int a,int b){nxt[++tot]=head[a];head[a]=tot;to[tot]=b;}
struct query{int dep,nxt;}a[N];
void Add(int x,int d,int id){a[id]=(query){d,Head[x]};Head[x]=id;}
inline void pre_dfs(int u){
    size[u]=1;
    for(int j=1;j<=18;++j)f[u][j]=f[f[u][j-1]][j-1];
    for(int i=head[u];i;i=nxt[i]){
        int v=to[i];dep[v]=dep[u]+1;f[v][0]=u;
        pre_dfs(v);size[u]+=size[v];
        if(size[v]>size[son[u]])son[u]=v;
    }
}
inline void update(int u,int val){
    sum[dep[u]]+=val;
    for(int i=head[u];i;i=nxt[i]){
        int v=to[i];if(visit[v])continue;
        update(v,val);
    }
}
inline void dfs(int u,int keep){
    for(int i=head[u];i;i=nxt[i]){
        int v=to[i];if(v==son[u])continue;
        dfs(v,0);
    }
    if(son[u])dfs(son[u],1),visit[son[u]]=1;update(u,1);
    for(int i=Head[u];i;i=a[i].nxt)ans[i]=sum[a[i].dep]-1;
    visit[son[u]]=0;if(!keep)update(u,-1);
}
int main(){
    n=read();
    for(int i=1;i<=n;++i){
        int x=read();
        if(!x)root[++root[0]]=i,dep[i]=1;
        else add(x,i);
    }
    for(int i=1;i<=root[0];++i)pre_dfs(root[i]);
    m=read();
    for(int i=1;i<=m;++i){
        int x=read(),k=read(),d=dep[x];
        for(int j=0;j<=18;++j)if(k&(1<

你可能感兴趣的:(CF208E Blood Cousins)