Ice_lift
2024-07-18 10:36:04
首先,我们发现同一个点的查询只需知道子树中每种颜色的数量就能一起得到答案,所以我们不妨将询问离线,一起考虑。
设
由于是次数统计,我们不妨考虑根号分治。
对于出现次数
对于出现次数
最终答案即为两部分的和。
时间复杂度为
PS:此题作者试了很多种方法,很多都因为
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 1;
const int M = 317 + 1;
int n, m, b;
int c[N], ct[N], tot;
vector<int> g[N];
int a[N];
vector<int > q[N], pp[N];
set<int> p[N];
int ans[N], cnt[N][M];
map<int, int> dfs (int u, int fa) {
map<int, int> res;
res[c[u]] ++;
if(res[c[u]] <= b) cnt[u][res[c[u]]] ++;
else p[u].insert(c[u]);
for (auto v : g[u]) {
if(v == fa) continue;
map<int, int> res2 = dfs(v, u);
if(res.size() < res2.size()) swap(res, res2), swap(cnt[u], cnt[v]), swap(p[u], p[v]);
for (auto x : res2) {
if(res[x.first] <= b) cnt[u][res[x.first]] --;
res[x.first] += x.second;
if(res[x.first] <= b) cnt[u][res[x.first]] ++;
else p[u].insert(x.first);
}
res2.clear();
}
for (auto x : q[u]) {
int k = a[x], id = x, xx = 0;
if(k <= b) for (int i = k; i <= b; i ++) xx += cnt[u][i];
for (auto y : p[u]) xx += (res[y] >= k);
ans[id] = xx;
}
return res;
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> m;
b = sqrt(n);
for (int i = 1; i <= n; i ++) cin >> c[i], ct[c[i]] ++;
for (int i = 1; i < n; i ++) {
int u, v;
cin >> u >> v;
g[u].push_back(v), g[v].push_back(u);
}
for (int i = 1, u; i <= m; i ++) {
cin >> u >> a[i];
q[u].push_back(i);
}
dfs(1, 0);
for (int i = 1; i <= m; i ++) cout << ans[i] << endl;
return 0;
}