[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;
}

猜你喜欢

转载自www.cnblogs.com/Neworld2002/p/10073791.html