CF208 E.Blood Cousins(樹上啓發式合併)

題目鏈接:CF208E
Polycarpus got hold of a family relationship tree. The tree describes family relationships of n people, numbered 1 through n. Each person in the tree has no more than one parent.

Let’s call person a a 1-ancestor of person b, if a is the parent of b.

Let’s call person a a k-ancestor (k > 1) of person b, if person b has a 1-ancestor, and a is a (k - 1)-ancestor of b’s 1-ancestor.

Family relationships don’t form cycles in the found tree. In other words, there is no person who is his own ancestor, directly or indirectly (that is, who is an x-ancestor for himself, for some x, x > 0).

Let’s call two people x and y (x ≠ y) p-th cousins (p > 0), if there is person z, who is a p-ancestor of x and a p-ancestor of y.

Polycarpus wonders how many counsins and what kinds of them everybody has. He took a piece of paper and wrote m pairs of integers vi, pi. Help him to calculate the number of pi-th cousins that person vi has, for each pair vi, pi.

Input
The first input line contains a single integer n (1 ≤ n ≤ 105) — the number of people in the tree. The next line contains n space-separated integers r1, r2, …, rn, where ri (1 ≤ ri ≤ n) is the number of person i’s parent or 0, if person i has no parent. It is guaranteed that family relationships don’t form cycles.

The third line contains a single number m (1 ≤ m ≤ 105) — the number of family relationship queries Polycarus has. Next m lines contain pairs of space-separated integers. The i-th line contains numbers vi, pi (1 ≤ vi, pi ≤ n).

Output
Print m space-separated integers — the answers to Polycarpus’ queries. Print the answers to the queries in the order, in which the queries occur in the input.

Examples
inputCopy
6
0 1 1 0 4 4
7
1 1
1 2
2 1
2 2
4 1
5 1
6 1
outputCopy
0 0 1 0 0 1 1

題意:給你一棵樹,輸入x,k。x代表節點,k代表深度,這裏的深度是以x爲基準,從下往上的深度
現在設y爲x在k深度下的祖先,現在問你和x同層的節點,有多少個祖先是y。

思路:感覺這是個超級有毒的題目,英語本來就不怎麼好,翻譯過來,我以爲題目是問有沒有超過k個堂兄弟,結果交上去還過了7組,拼命想bug,然而題目都看錯了,怎麼改也會是錯的,於是百度題意,得到正確的題意後,發現這個題目需要轉換,變成祖先的第k深度下有多少個孩子。所有我們需要去找節點的祖先,第一個想的方法肯定是定義一個fa數組保存每個節點祖先,然後對每個查詢,遞推查祖先就可以了,但是這個會超時,因爲可能這棵樹可能會是一條深度爲1e5的鏈,所以需要優化,開一個vector fa[max]數組,在dfs時,把節點的每個祖先都存起來,這樣也不行,爆內存。。。。,最後,熟悉dfs的過程可以發現,根本不需要二維數組,用一維數組就可以了。

代碼:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ULL unsigned long long
#define LL long long
#define Max 1000005
#define mem(a,b) memset(a,b,sizeof(a));
#define pb push_back
#define mp make_pair
#define input ios::sync_with_stdio(false);cin.tie(0);
#define debug printf("debug!!!\n");
const LL mod=1e9+7;
const ULL base=131;
const LL LL_MAX=9223372036854775807;
using namespace std;
struct node {
    int to,next;
} edge[Max];
struct ans {
    int to,next;
    int ans,fa;
} query[Max];

int head[Max],tot;
int qhead[Max],num;
int Son;
int cnt[Max],son[Max],dep[Max],Size[Max];
int ind[Max];
vector<int> fat[Max];
void init() {
    tot=0;
    num=0;
    mem(head,-1);
    mem(qhead,-1);
}
void addedge(int u,int v) {
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
void addquery(int  u,int cot) {
    query[num].to=cot;
    query[num].next=qhead[u];
    qhead[u]=num++;
}

void getsd(int u,int fa,int d) {
    dep[u]=d,Size[u]=1;
    ind[dep[u]]=u;
    for(int t=qhead[u];t!=-1;t=query[t].next){
        int to=query[t].to;
        if(dep[u]-to<=0)
            query[t].fa=0;
        else
            query[t].fa=ind[dep[u]-to];
    }
    for(int t=head[u]; t!=-1; t=edge[t].next) {
        int to=edge[t].to;
        if(to!=fa){
            getsd(to,u,d+1);
            Size[u]+=Size[to];
            if(Size[to]>Size[son[u]])
                son[u]=to;
        }
    }
}
void add(int u,int fa,int val) {
    cnt[dep[u]]+=val;
    for(int t=head[u]; t!=-1; t=edge[t].next) {
        int to=edge[t].to;
        if(to!=fa && to!=Son) {
            add(to,u,val);
        }
    }
}
void dfs(int u,int fa,int keep) {
    for(int t=head[u]; t!=-1; t=edge[t].next) {
        int to=edge[t].to;
        if(to!=fa && to!=son[u])
            dfs(to,u,0);
    }
    if(son[u])
        dfs(son[u],u,1),Son=son[u];
    add(u,fa,1);
    Son=0;
    for(int t=qhead[u]; t!=-1; t=query[t].next) {
        int to=query[t].to;
        if(u==0) {
            query[t].ans=0;
        } else {
            query[t].ans+=cnt[dep[u]+to];
        }
    }
    if(!keep)
        add(u,fa,-1);
}
int main()
{
    init();
    int n;
    scanf("%d",&n);
    for(int i=1; i<=n; i++) {
        int fa;
        scanf("%d",&fa);
        addedge(fa,i);
        addedge(i,fa);
    }
    int m;
    scanf("%d",&m);
    while(m--) {
        int u,k;
        scanf("%d%d",&u,&k);
        addquery(u,k);
    }
    getsd(0,-1,0);
    int len=num;
    num=0;
    mem(qhead,-1);
    for(int i=0;i<len;i++)
        addquery(query[i].fa,query[i].to);
    dfs(0,-1,1);
    for(int i=0; i<num; i++)
        printf("%d ",query[i].ans==0?0:(query[i].ans-1));
    printf("\n");
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章