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\n", _qs[i].Ans);
    return 0;
}

  

posted @ 2018-08-16 17:38  headboy2002  阅读(92)  评论(0编辑  收藏  举报