1. 程式人生 > >codeforces 208E Blood Cousins (dsu on tree + 倍增 )

codeforces 208E Blood Cousins (dsu on tree + 倍增 )

題意: 現在有若干棵樹,對於每次一詢問,都有一個節點 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;
}


/*

*/