CF375D (树上启发式合并)
就是给你一棵树,树上每个节点都有一个颜色,在你m次询问每次询问给你一个节点u和一个数字k,问你在u这颗子树里面又少种颜色的结点个数是大于k;
- 依然是把询问离线到启发式合并的过程中。但是每次询问的k是不确定的,如何统计数量大于等于k的颜色数目?
- 我们用树状数组维护出现x次的颜色个数。每经过一个节点cnt[col[u]] 减1,cnt[col[u]] + val 加1.
- 这样就能logn统计答案,总时间复杂度nlognlogn
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
const int N = 1e6 + 5;
const int M = 1e6 + 5;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
int n, m;
int col[N];
int h[N], e[N << 1], ne[N << 1], idx;
int sz[N], son[N], flag, cnt[N];
int ans[N];
struct node {
int val, id;
};
vector<node>Q[N];
int tree[N];
int lowbit(int x) {
return (-x) & x;
}
void update(int pos, int val) {
for(; pos <= 100002; pos += lowbit(pos)) tree[pos] += val;
}
int query(int pos) {
int res = 0;
for(; pos; pos -= lowbit(pos)) res += tree[pos];
return res;
}
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void dfs(int u, int fa) {
sz[u] = 1;
for ( int i = h[u]; ~i; i = ne[i] ) {
int v = e[i]; if(v == fa) continue;
dfs(v, u);
sz[u] += sz[v];
if(sz[v] > sz[son[u]]) son[u] = v;
}
}
void count (int u, int fa, int val) {
if(cnt[col[u]]) update(cnt[col[u]], -1);
cnt[col[u]] += val;
if(cnt[col[u]]) update(cnt[col[u]], 1);
for ( int i = h[u]; ~i; i = ne[i] ) {
int v = e[i]; if(v == fa || v == flag) continue;
count(v, u, val);
}
}
void dfs (int u, int fa, bool keep) {
for ( int i = h[u]; ~i; i = ne[i] ) {
int v = e[i]; if(v == fa || v == son[u]) continue;
dfs(v, u, false);
}
if(son[u]) {
dfs(son[u], u, true); flag = son[u];
}
count(u, fa, 1);
flag = 0;
for ( auto i : Q[u] ) {
ans[i.id] = query(n) - query(i.val - 1);
}
if(!keep) {
count(u, fa, -1);
}
}
int main () {
IOS
memset(h, -1, sizeof h);
cin >> n >> m;
for ( int i = 1; i <= n; ++ i ) cin >> col[i];
for ( int i = 1; i <= n - 1; ++ i ) {
int u, v; cin >> u >> v; add(u, v); add(v, u);
}
for (int i = 1; i <= m; ++ i ) {
int v, k; cin >> v >> k;
Q[v].push_back({k, i});
}
dfs(1, 0);
dfs(1, 0, 0);
for ( int i = 1; i <= m; ++ i ) cout << ans[i] << '\n';
cout << '\n';
return 0;
}