SPOJ - DQUERY(区间不同数+树状数组)

链接:SPOJ - DQUERY

题意:求给定区间不同数的个数(不更新)。

题解:离线+树状数组。

   对所求的所有区间(l, r)根据r从小到大排序。从1-n依次遍历序列数组,在树状数组中不断更新a[i]出现的最后一个位置。更新:将a[i]所在位置i在树状数组中加1(add(i, 1)),并消去a[i]上次出现的位置上的1(add(lasta[i], -1))。当遍历到i == r时,就保存答案(sum[r] - sum[l-1])。

 

#include<bits/stdc++.h>
using namespace std;

const int maxn = 2e6 + 10;
int n, q;
int a[maxn];
int bit[maxn];
struct Node{
    int l, r, id;
    bool operator < (const Node& A) const
    {
        return r < A.r;
    }
}p[maxn];
int last[maxn];
int ans[maxn];

void add(int i, int x)
{
    while(i > 0 && i < maxn){
        bit[i] += x;
        i += i & -i;
    }
}

int sum(int i)
{
    int ans = 0;
    while(i){
        ans += bit[i];
        i -= i & -i;
    }
    return ans;
}

int main()
{
    while(scanf("%d", &n) != EOF){

        memset(bit, 0, sizeof(bit));
        memset(last, -1, sizeof(last));
        int tot = 0;
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
        scanf("%d", &q);
        for(int i = 0; i < q; i++){
            scanf("%d%d", &p[i].l, &p[i].r);
            p[i].id = i;
        }
        sort(p, p + q);     //区间排序

        memset(ans, 0, sizeof(ans));
        for(int i = 1, k = 0; i <= n; i++){
            //更新a[i]出现的最后一个位置
            if(last[a[i]] != -1){
                add(last[a[i]], -1);
                add(i, 1);
                last[a[i]] = i;
            }
            else{
                last[a[i]] = i;
                add(i, 1);
            }
        
            //保存答案
            while(k < q && p[k].r == i){
                ans[p[k].id] = sum(p[k].r) - sum(p[k].l - 1);
                k++;
            }
        }

        for(int i = 0; i < q; i++) printf("%d\n", ans[i]);
    }
}

 

posted @ 2018-07-20 11:33  鬼沐冢  阅读(243)  评论(0)    收藏  举报