• [BZOJ 1878] [SDOI2009] HH的项链


    题目链接: BZOJ - 1878

    题目分析

    题目的询问是某个区间内的颜色种类数,所以我们希望这个区间内的每种颜色只被计数一次,那么我们就选取询问区间内的每种颜色第一次出现的元素计数,之后再出现已经在询问区间中出现过的颜色就不再计数。考虑一种离线算法,如果我们将所有询问按照询问区间的左端点排序,那么所有询问的左端点就是不递减的,一直向右推移。开始时预处理出每个元素后面第一个与它颜色相同的元素是哪一个,并将所有出现的颜色的第一个元素加入到树状数组中。那么开始时维护的区间就是从 1 开始的。每次处理一个询问,如果当前维护的区间左端点比询问的区间左端点靠左,那么就应该将左端点向右推移到询问的左端点。每次将左端点向右移动一格,一个元素被移除,这时它一定是它的颜色在此时维护的区间中的第一个元素,所以它一定存在于树状数组中,那么我们就将它在树状数组中删除,再将它的下一个与它同色的元素加入到树状数组中。然后对于以现在维护的左端点 L 为左端点的询问 (L, R),只要用树状数组查询R的前缀和 Get(R) 就是答案,这个前缀和中所有的元素都是从 L 开始的区间中某种颜色第一次出现的位置,不会有某种颜色重复计数的情况。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
     
    using namespace std;
     
    const int MaxN = 50000 + 5, MaxQ = 200000 + 5, MaxType = 1000000 + 5;
     
    int n, m, a, b;
    int A[MaxN], Next[MaxN], T[MaxN], Last[MaxType], Ans[MaxQ];
     
    struct Query
    {
        int l, r, num;
    } Q[MaxQ];
     
    bool cmp(Query q1, Query q2) {
        return q1.l < q2.l;
    }
     
    void Add(int x, int num) {
        for (int i = x; i <= n; i += i & (-i)) 
            T[i] += num; 
    }
     
    int Get(int x) {
        int ret = 0;
        for (int i = x; i >= 1; i -= i & (-i)) 
            ret += T[i];
        return ret;
    }
     
    int main() 
    {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) scanf("%d", &A[i]);
        scanf("%d", &m);
        for (int i = 1; i <= m; i++) {
            scanf("%d%d", &a, &b);
            Q[i].l = a; Q[i].r = b;
            Q[i].num = i;
        }
        sort(Q + 1, Q + m + 1, cmp);
        memset(T, 0, sizeof(T));
        memset(Last, 0, sizeof(Last));
        for (int i = 1; i <= n; i++) {
            if (Last[A[i]] == 0) Add(i, 1);
            else Next[Last[A[i]]] = i;
            Last[A[i]] = i;
        }
        int x = 1;
        for (int i = 1; i <= m; i++) {
            while (x < Q[i].l) {
                Add(x, -1);
                if (Next[x]) Add(Next[x], 1);
                ++x;
            }
            Ans[Q[i].num] = Get(Q[i].r);
        }
        for (int i = 1; i <= m; i++) printf("%d
    ", Ans[i]);
        return 0;
    }
    
  • 相关阅读:
    字符串去特定字符
    字符串的查找删除
    输出梯形
    元素节点的 innerText、innerHTML、outerHTML、outerText
    JavaScript DOM 特殊集合Collection
    Collection 访问方式
    JS Browser BOM
    异常
    JCBD
    try-with-resources 方式关闭注意事项
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4172885.html
Copyright © 2020-2023  润新知