Codeforces Round #221 (Div. 1) D Tree and Queries(树上启发式合并 + 树状数组)

D. Tree and Queries

time limit per test

1 second

memory limit per test

256 megabytes

input

standard input

output

standard output

You have a rooted tree consisting of n vertices. Each vertex of the tree has some color. We will assume that the tree vertices are numbered by integers from 1 to n. Then we represent the color of vertex v as cv. The tree root is a vertex with number 1.

In this problem you need to answer to m queries. Each query is described by two integers vj, kj. The answer to query vj, kj is the number of such colors of vertices x, that the subtree of vertex vj contains at least kj vertices of color x.

You can find the definition of a rooted tree by the following link: http://en.wikipedia.org/wiki/Tree_(graph_theory).

Input

The first line contains two integers n and m (2 ≤ n ≤ 105; 1 ≤ m ≤ 105). The next line contains a sequence of integers c1, c2, ..., cn (1 ≤ ci ≤ 105). The next n - 1 lines contain the edges of the tree. The i-th line contains the numbers ai, bi (1 ≤ ai, bi ≤ nai ≠ bi) — the vertices connected by an edge of the tree.

Next m lines contain the queries. The j-th line contains two integers vj, kj (1 ≤ vj ≤ n; 1 ≤ kj ≤ 105).

Output

Print m integers — the answers to the queries in the order the queries appear in the input.

Examples

input

Copy

8 5
1 2 2 3 3 2 3 3
1 2
1 5
2 3
2 4
5 6
5 7
5 8
1 2
1 3
1 4
2 3
5 3

output

Copy

2
2
1
0
1

input

Copy

4 1
1 2 3 4
1 2
2 3
3 4
1 1

output

Copy

4

Note

A subtree of vertex v in a rooted tree with root r is a set of vertices {u : dist(r, v) + dist(v, u) = dist(r, u)}. Where dist(x, y) is the length (in edges) of the shortest path between vertices x and y.

题目大意 :
一棵根为1的树,每个点都有颜色,查询点x为根的子树中,有多少种颜色的数量 >= k

解法 :

对于每个点的颜色信息(颜色种类和数量),可以通过离线 + 启发式合并来处理,颜色只有1e5,求数量大于等于k提示了要用树状数组记后缀和;但是如果求的过程中,换了一个孩子,这个根的上一个孩子的信息仍然保存在树状数组中,这时候只要在递归这个孩子之前,将需要查询的答案先保存下来,当递归完该孩子后,此时的答案减去保存的答案,就是本次递归的答案了!

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; }

unordered_map <int, int> mp[N]; // 下标,颜色,次数
vector <int> G[N << 1];
vector <pir> q[N]; // 答案下标,查询的k
int a[N], ans[N];

int d[N], M;  // 颜色数量出现次数,后缀和
void add(int x, int y) {
	if (!x)
		return;
	x = N - x;
	while (x <= N) {
		d[x] += y;
		x += lowbit(x);
	}
}
int Ask(int x) {
	int tot = 0;
	x = N - x;
	while (x) {
		tot += d[x];
		x -= lowbit(x);
	}
	return tot;
}

void dfs(int x, int fa) {
	vector <int> vec;
	for (int i = 0; i < SZ(q[x]); i++)
		vec.push_back(Ask(q[x][i].second)); // 递归前答案

	if (mp[x].count(a[x]))
		add(mp[x][a[x]], -1);
	mp[x][a[x]]++, add(mp[x][a[x]], 1);  // 加上本身
	for (auto v : G[x]) {
		if (v == fa)
			continue;
		dfs(v, x);
		if (SZ(mp[v]) > SZ(mp[x]))
			swap(mp[x], mp[v]);
		for (auto it : mp[v]) {
			int num = it.second; // 失去该次数
			add(num, -1);     
			if (mp[x].count(it.first))
				add(mp[x][it.first], -1);  // 失去该次数
			mp[x][it.first] += num;   // 合并后的次数 + 1
			add(mp[x][it.first], 1);
		}
	}
	for (int i = 0; i < SZ(q[x]); i++)  // 减去更新前的值
		ans[q[x][i].first] = Ask(q[x][i].second) - vec[i];
}

int main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
		sc("%d", &a[i]), Max(M, a[i]);
	for (int i = 1; i < n; i++) {
		int u, v;
		sc("%d %d", &u, &v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	for (int i = 1; i <= m; i++) {
		int u, k;
		sc("%d %d", &u, &k);
		q[u].push_back({ i, k });
	}

	dfs(1, 0);
	for (int i = 1; i <= m; i++)
		printf("%d\n", ans[i]);
	return 0;  // 改数组大小!!!用pair记得改宏定义!!!
}

猜你喜欢

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