Codeforces Round #130 (Div. 2) E 树上倍增 + 两次二分

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 xx > 0).

Let's call two people x and y (x ≠ yp-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 ip i. Help him to calculate the number of p i-th cousins that person v i has, for each pair v ip 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 ip 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记得改宏定义!!!
}

猜你喜欢

转载自blog.csdn.net/weixin_43851525/article/details/105706641