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;
}
posted @ 2022-03-30 15:36  qingyanng  阅读(82)  评论(0编辑  收藏  举报