BZOJ 1878 [SDOI2009]HH的项链(扫描线+树状数组)

 

【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=1878

 

【题目大意】

  给出一个数列,给出m个查询,每次查询一个区间中不相同的数字个数

 

【题解】

  我们记录每一个位置上下一个相同相同元素的位置,当扫描线扫过当前点时
  我们消除这个点的影响,并在其下个出现的位置进行更新,
  这样就能求出固定左端点在不同右端点情况下不同区间内不同元素的数量
  离线处理可得各区间解。

 

【代码】

#include <cstdio>
#include <algorithm>
using namespace std;
const int N=1000010;
int n,m,c[N],a[N],pre[N],nxt[N],ans[N];
struct data{int l,r,id;}p[N];
bool cmp(data a,data b){return a.l<b.l;}
void add(int x,int val){while(x<=n+1)c[x]+=val,x+=x&-x;}
int query(int x){int s=0;while(x)s+=c[x],x-=x&-x;return s;}
int main(){
    while(~scanf("%d",&n)){
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),c[i]=0;
        for(int i=1;i<N;i++)pre[i]=n+1;
        for(int i=n;i;i--){
            nxt[i]=pre[a[i]];
            pre[a[i]]=i;
        }
        for(int i=1;i<N;i++)add(pre[i],1);
        scanf("%d",&m);
        for(int i=1;i<=m;i++)scanf("%d%d",&p[i].l,&p[i].r),p[i].id=i;
        sort(p+1,p+m+1,cmp);
        int t=1;
        for(int i=1;i<=m;i++){
            while(t<p[i].l){
                add(t,-1);
                add(nxt[t],1);
                t++;
            }ans[p[i].id]=query(p[i].r);
        }
        for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
    }return 0;
}
posted @ 2017-03-27 23:54  forever97  阅读(142)  评论(0编辑  收藏  举报