• cf375 D Tree and Queries


    传送门
    感觉挺套路的吧。给出一棵树,然后查询子树里面出现次数大于等于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
    ", Ans[i]);
        return 0;
    }
    
    I‘m Stein, welcome to my blog
  • 相关阅读:
    非常实用的原创小工具:EasyIP
    ORACLE日期时间函数大全
    Windows 下单机最大TCP连接数
    如何自动以管理员身份运行.NET程序?
    ExecuteScalar 返回值问题
    Assembly类
    .Net字符串驻留池
    进程Process
    C#连接Oracle数据库(直接引用dll使用)
    谈Linux与Windows的比较
  • 原文地址:https://www.cnblogs.com/Emcikem/p/14381477.html
Copyright © 2020-2023  润新知