[SDOI2009] HH的项链(待续)

[SDOI2009] HH的项链(待续)

题目大意:对一个由若干个数字(可重复)组成的数列,询问\([l,r]\)中出现的不同的数字数量

考试时(考试时范围小)用的暴力,but,没有考虑数字0的情况,炸掉。

Solution.1

  • 读入,将询问按照右端点从小到大排序,左端点如何不考虑
  • 因为按照\(r\)推进,我们只需要考虑新的数字,所以当一个数字比它之前出现的位置靠右,我们只记录这一个
  • 用树状数组来维护

Code.1

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define lowbit(x) x & -x

using std::sort;

const int N = 1e6 + 10; 

struct Q{
    int l, r, num;
}a[N];

int bit[N], shell[N], last[N], A[N];
int n, m, nowr;

inline bool cmp(Q a, Q b){
	return a.r < b.r;
}

inline int ask(int x){
    int ans = 0;
    for(; x; x -= lowbit(x)){
        ans += bit[x];
    }
    return ans;
}

inline void ins(int x, int y){
    for(; x <= n; x += lowbit(x)){
        bit[x] += y;
    }
}

int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i){
        scanf("%d", &shell[i]);
    }
    scanf("%d", &m);
    for(int i = 1; i <= m; ++i){
        scanf("%d %d", &a[i].l, &a[i].r);
        a[i].num = i;
    }
    sort(a + 1, a + m + 1, cmp);//排序
    for(int i = 1; i <= m; ++i){
        while(nowr < a[i].r){//核心代码,last表示此数字上一次出现的位置
            nowr++;//shell表示此位置出现的数字
            if(last[shell[nowr]])
                ins(last[shell[nowr]], -1);
            ins(nowr, 1);
            last[shell[nowr]] = nowr;
        }
        A[a[i].num] = ask(a[i].r) - ask(a[i].l - 1);
    }
    for(int i = 1; i <= m; ++i){
        printf("%d\n", A[i]);
    } 
    return 0;
} 

解法2:

用莫队;

莫队算法可用于解决一类可离线且在得到区间\([l,r]\)的答案后,能在\(O(1)\)\(O(log2n)\)得到区间\([l,r+1]\)\([l−1,r]\)的答案的问题

解法3:

主席树

posted @ 2018-08-29 11:29  LMSH7  阅读(86)  评论(0编辑  收藏  举报