cf375 D Tree and Queries - 莫队 + dfs序

传送门
感觉挺套路的吧。给出一棵树,然后查询子树里面出现次数大于等于k的颜色个数。

因为是求子树问题,看一眼就知道是用dfs序把树变成一个序列。
然后统计就用莫队去求。

开始我憨批地想维护下前缀和,然后发现树状数组是只改变后缀和的,然后改了强制把树状数组维护成了前缀和。

但发现好像多了一个数字,记录下sum[cnt[a[x]]]++,不就行了吗。
然后发现我树状数组的两个操作就是这个意思。

没啥好说的,就是个套路题。看一眼就知道的题。

但注意下树上莫队是记录树上任意两点,而莫队+dfs序是记录子树的问题。

#include <bits/stdc++.h>
using namespace std;
template<typename T = long long> inline T read() {
    T s = 0, f = 1; char ch = getchar();
    while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
    while(isdigit(ch)) {s = (s << 3) + (s << 1) + ch - 48; ch = getchar();} 
    return s * f;
}
const int N = 1e5 + 5, M = 1e6 + 5, MOD = 1e9 + 7, CM = 998244353, INF = 0x3f3f3f3f;
int a[N], col[N];
struct Edge{
    int to, next;
}e[M << 1];
int head[N], tot;
void add(int u, int v){
    e[++tot].to = v;
    e[tot].next = head[u];
    head[u] = tot;
}
int l[N], r[N], id, bl[N];
void dfs(int u, int fath){
    l[u] = ++id;
    for(int i = head[u]; i; i = e[i].next) {
        int v = e[i].to;
        if(v == fath) continue;
        dfs(v, u);
    }
    r[u] = id;
}
struct Query{
    int l, r, id, k; 
} q[N];
bool cmp(const Query &a, const Query &b) {
    return (bl[a.l] ^ bl[b.l]) ? bl[a.l] < bl[b.l] : ((bl[a.l] & 1) ? a.r < b.r : a.r > b.r);
}
int nowl = 1, nowr = 0, cnt[N], Ans[N], sum[N];
void add(int x) {
    ++cnt[a[x]];
    if(cnt[a[x]] >= 0) sum[cnt[a[x]]]++;
}
void del(int x) {
    if(cnt[a[x]] >= 0) sum[cnt[a[x]]]--;
    --cnt[a[x]];
}
int main(){
    int n = read(), m = read();
    for(int i = 1; i <= n; i++) col[i] = read();
    for(int i = 1; i < n; i++) {
        int u = read(), v = read();
        add(u, v), add(v, u);
    }
    dfs(1, 0);
    for(int i = 1; i <= n; i++) a[l[i]] = col[i];
    for(int i = 1; i <= m; i++) {
        int u, k;
        scanf("%d%d", &u, &k);
        q[i] = {l[u], r[u], i, k};
    }
    int unt = sqrt(n);
    for(int i = 1; i <= n; i++) bl[i] = (i - 1) / unt + 1;
    sort(q + 1, q + m + 1, cmp);
    for(int i = 1; i <= m; i++) {
        while(nowl < q[i].l) del(nowl++);
        while(nowl > q[i].l) add(--nowl);
        while(nowr < q[i].r) add(++nowr);
        while(nowr > q[i].r) del(nowr--);
        Ans[q[i].id] = sum[q[i].k];
    }
    for(int i = 1; i <= m; i++) printf("%d\n", Ans[i]);
    return 0;
}
posted @ 2021-02-06 14:45  Emcikem  阅读(59)  评论(0编辑  收藏  举报