• luogu1972 [SDOI2009] HH的项链


    题目大意

      给一段长度n(n<=100000)序列,每次询问一段区间(个数<=200000),问区间中的数字种数。

    题解

      本题特别之处在于区间内的数字种数不满足区间的相加性,所以我们可以加约束条件。我们不妨考虑维护一个树状数组维护数字种数。显然当询问的r固定时,对于每一个数值,我们只保留其在[1,r]内最右侧的数字,将其它数字删除,这样对结果没有影响,反而数字的个数满足区间可加性了。所以定义树状数组维护的前缀和值为满足约束条件——对于每个数值只保留位置最右侧的数字——时,[1,r]中仍然存在的数字的个数。

      因此,我们将所有询问按照右端点排序,当树状数组负责的右端点要向右延伸时,要在树状数组中把右端点的数值与其相等、位置位于它左侧的位置(解决的办法貌似叫做“链式前向星”?)对应前缀和更新-1,将右端点所在位置对应前缀和更新+1即可。

      一定要注意查询是排过序的,输出时要按照原有的顺序输出!!!!!

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int MAX_LEN = 500010, MAX_VAL = 1000010, MAX_QUERY = 200010;
    int OrgData[MAX_LEN], EqValPrev[MAX_LEN];
    int Len, TotQuery;
    
    struct BIT
    {
    private:
        int C[MAX_LEN];
        int N;
    
        int Lowbit(int x)
        {
            return x & -x;
        }
    
    public:
        BIT(int n):N(n){}
    
        void Update(int p, int val)
        {
            if (p == 0)
                return;
            while (p <= N)
            {
                C[p] += val;
                p += Lowbit(p);
            }
        }
    
        int Query(int p)
        {
            int ans = 0;
            while (p >= 1)
            {
                ans += C[p];
                p -= Lowbit(p);
            }
            return ans;
    
        }
    };
    
    struct Query
    {
        int L, R, Ans;
    }_qs[MAX_QUERY], *SortedQ[MAX_QUERY];
    
    bool Cmp_R(Query *a, Query *b)
    {
        return a->R < b->R;
    }
    
    void GetEqValPrev()
    {
        static int valPrev[MAX_VAL];
        for (int i = 1; i <= Len; i++)
        {
            EqValPrev[i] = valPrev[OrgData[i]];
            valPrev[OrgData[i]] = i;
        }
    }
    
    int main()
    {
        scanf("%d", &Len);
        for (int i = 1; i <= Len; i++)
            scanf("%d", OrgData + i);
        scanf("%d", &TotQuery);
        for (int i = 1; i <= TotQuery; i++)
            scanf("%d%d", &_qs[i].L, &_qs[i].R);
    
        static BIT g(Len);
        for (int i = 1; i <= TotQuery; i++)
            SortedQ[i] = _qs + i;
        sort(SortedQ + 1, SortedQ + TotQuery + 1, Cmp_R);
        GetEqValPrev();
        int curR = 0;
        for (int i = 1; i <= TotQuery; i++)
        {
            while (curR < SortedQ[i]->R)
            {
                curR++;
                g.Update(EqValPrev[curR], -1);
                g.Update(curR, 1);
            }
            SortedQ[i]->Ans = g.Query(SortedQ[i]->R) - g.Query(SortedQ[i]->L - 1);
        }
        for (int i = 1; i <= TotQuery; i++)
            printf("%d
    ", _qs[i].Ans);
        return 0;
    }
    

      

  • 相关阅读:
    Android 中Base64的操作
    android 异步图片处理 工具类
    android 跨应用跳转 启动其他应用指定界面
    C++代码案例
    Android 中 Base64的操作应用
    Python基础笔记1
    [linux] 大批量删除任务
    Python基础笔记3
    [R] 如何快速生成许多差异明显的颜色?
    Python基础笔记4
  • 原文地址:https://www.cnblogs.com/headboy2002/p/9488711.html
Copyright © 2020-2023  润新知