E. Blood Cousins
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
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 v i, p i. Help him to calculate the number of p i-th cousins that person v i has, for each pair v i, p i.
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 r 1, r 2, ..., r n, where r i (1 ≤ r i ≤ 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 v i, p i (1 ≤ v i, p i ≤ 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
input
Copy
6
0 1 1 0 4 4
7
1 1
1 2
2 1
2 2
4 1
5 1
6 1
output
Copy
0 0 1 0 0 1 1
题目大意:
一棵树代表了一个家族的族谱,他们可能没有共同的祖先(根结点不算一个人),每次询问与点X第K代父亲相同的兄弟数量
解法:
找点X的第K代父亲Y与LCA原理一样,可以先DFS预处理,然后倍增查找;找兄弟意味着点集的深度与X相同,但是都存在于Y的子树中,问题就转换成了询问深度为dep[X]的Y的孩子数量 - 1,在预处理的过程中,利用DFS序维护一下每个点的子树,最后两次二分左边界和右边界即可。
Accepted code
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
#define sc scanf
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define pir pair <int, int>
#define MK(x, y) make_pair(x, y)
#define MEM(x, b) memset(x, b, sizeof(x))
#define MPY(x, b) memcpy(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))
typedef long long ll;
const int MOD = 1e9 + 7;
const int N = 1e5 + 100;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
inline ll dpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % MOD; b >>= 1; t = (t*t) % MOD; }return r; }
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t); b >>= 1; t = (t*t); }return r; }
vector <int> G[N << 1], s[N];
int f[N][25], dep[N], n, q;
int L[N], R[N], cnt;
int dis[N];
map <pir, int> ans;
void dfs(int x, int fa, int dp) {
dep[x] = dp;
f[x][0] = fa;
L[x] = ++cnt;
s[dp].push_back(x);
for (int i = 1; (1 << i) <= dep[x]; i++)
f[x][i] = f[f[x][i - 1]][i - 1];
for (auto v : G[x]) {
dis[v] = dis[x] + 1;
dfs(v, x, dp + 1);
}
R[x] = cnt;
}
int mul(int x, int p) { // 倍增查找第K代父亲
int mid = x;
for (int i = 20; i >= 0; i--) {
if (f[mid][i] && dis[x] - dis[f[mid][i]] <= p)
mid = f[mid][i];
}
return mid;
}
int Calc(int x, int dp) {
if (ans.count(MK(x, dp)) != NULL) // 查询过直接输出答案,防止超时
return ans[MK(x, dp)];
int l = 0, r = SZ(s[dp]) - 1, start = SZ(s[dp]);
while (l <= r) { // 二分左端点
int mid = (l + r) >> 1;
if (L[s[dp][mid]] >= L[x])
start = mid, r = mid - 1;
else
l = mid + 1;
}
l = 0, r = SZ(s[dp]) - 1;
int end_ = -1;
while (l <= r) { // 二分右端点
int mid = (l + r) >> 1;
if (R[s[dp][mid]] <= R[x])
end_ = mid, l = mid + 1;
else
r = mid - 1;
}
int tot = end_ - start + 1; // 孩子数量
if (tot < 1)
return ans[MK(x, dp)] = 0;
else
return ans[MK(x, dp)] = tot;
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++) {
int u;
sc("%d", &u);
if (u == 0)
u = n + 1; // 不算祖先
G[u].push_back(i);
}
dfs(n + 1, 0, 1);
cin >> q;
while (q--) {
int u, p;
sc("%d %d", &u, &p);
int x = mul(u, p); // 第K代父亲
if (x == n + 1)
printf("0 ");
else
printf("%d ", Calc(x, dep[u]) - 1);
}
printf("\n");
return 0; // 改数组大小!!!用pair记得改宏定义!!!
}