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記得改宏定義!!!
}

 

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