• Luogu4113 采花(树状数组)题解


    题意

    给出一个序列与若干个区间,求每一个区间内出现次数大于等于2的数的个数

    算法

    树状数组离线(连主席树都敢卡……

    思路

    求出现次数的题,基本都是这个套路 e.g.Luogu1972 HH的项链

    考虑对于区间(l-r),每一种颜色只有倒数第二个对答案有影响(因为这是该颜色最晚可以被计入答案的位置,当询问的左端点超过这个值时,该颜色就没用了),因此维护一个(nxt_{1-n}),记录(i)号位置上的颜色的前一个相同颜色的位置,当某一颜色出现次数超过(2)时,就在(nxt_i)(+1)(注意不是在(i),因为只有它自己时不算入答案),并且在(nxt_{nxt_i})(-1)来更新。同时,为了不对之前的询问造成影响,要先将答案离线下来并以右端点排序。

    代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    
    const int maxn = 2e6 + 10;
    int n,C,c[maxn],m,nxt[maxn],a[maxn],T[maxn],ans[maxn],vis[maxn];
    struct Que{
        int l,r,id;
    }q[maxn];
    
    int lowbit(int x){return x & (-x);}
    
    void add(int x, int val){
        for(int i = x; i <= n; i += lowbit(i))
            c[i] += val; 
    }
    
    int query(int x){
        int ans = 0;
        for(int i = x; i; i -= lowbit(i))
            ans += c[i];
        return ans;
    }
    
    bool cmp(Que x, Que y){return x.r < y.r;}
    
    int main(){
        scanf("%d%d%d", &n, &C, &m);
        for(int i = 1; i <= n; ++ i) scanf("%d", a + i);
        for(int i = 1; i <= n; ++ i){
            if(T[a[i]]) nxt[i] = T[a[i]];
            T[a[i]] = i;
        } memset(T,0,sizeof(T));
        for(int i = 1; i <= m; ++ i) scanf("%d%d", &q[i].l, &q[i].r), q[i].id = i;
        sort(q + 1, q + 1 + m, cmp);
        int now = 0;
        for(int i = 1; i <= m; ++ i){
            while(now + 1 <= q[i].r){
                now ++; 
                if(T[a[now]] >= 1){
                    if(nxt[nxt[now]]) add(nxt[nxt[now]], -1);
                    add(nxt[now], 1);
                }
                else T[a[now]] += 1;
            } 
            ans[q[i].id] = query(q[i].r) - query(q[i].l - 1);
        }
        for(int i = 1; i <= m; ++ i) printf("%d
    ", ans[i]);
        return 0;
    }
    

    总结

    关于这类卡的很死的区间出现次数的问题,可以使用树状数组解答,主要思考如何统计对答案的影响并更新树状数组。

  • 相关阅读:
    FZU OJ 1056 :扫雷游戏
    HPU 1166: 阶乘问题(一)
    常用的一些模板
    PAT天梯:L1-019. 谁先倒
    HPU 1437: 王小二的求值问题
    《编程珠玑》阅读小记(7) — 代码调优与节省空间
    《编程珠玑》阅读小记(6) — 算法设计技术
    《编程珠玑》阅读小记(5) — 编程小事
    《编程珠玑》阅读小记(4) — 编写正确的程序
    《C/C++专项练习》— (1)
  • 原文地址:https://www.cnblogs.com/whenc/p/13869784.html
Copyright © 2020-2023  润新知