1. 程式人生 > >[luogu1972][SDOI2009]HH的項鍊

[luogu1972][SDOI2009]HH的項鍊

傳送門

開始用莫隊水了90分。

想了很久還是沒想出來,於是看了一眼題解。妙!實在妙!

考慮一個數字只被算一次?那麼其他的數應該被刪掉。

對於一個固定的右區間端點,顯然刪的數越往後越好。

於是考慮把所有詢問的區間按右端點排序,然後開始掃一遍。用樹狀陣列維護字首和。

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

struct Node {
    int l,r,num;
}G[MAXN];
int C[MAXN<<1],a[MAXN],book[MAXN<<1];
int ans[MAXN];
int N,M;

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

inline void update(int x,int u) {
    for(;x<=N;x+=lowbit(x)) C[x] += u;
}

inline int query(int u) {
    int ans = 0;
    for(;u>=1;u-=lowbit(u)) ans += C[u];
    return ans;
}

int main() {

    std::memset(book,0,sizeof(book));
    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",&G[i].l,&G[i].r);
        G[i].num = i;
    }

    std::sort(G+1,G+1+M,cmp);

    int last = 0;
    for(int i=1;i<=M;++i) {

        for(;last+1<=G[i].r;) {
            last++;
            if(book[a[last]]) update(book[a[last]],-1);
            book[a[last]] = last;
            update(last,1);
        }

        ans[G[i].num] = query(G[i].r) - query(G[i].l-1);
    }

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