[BZOJ] 1878: [SDOI2009]HH的项链

题意:给一个序列,多次询问一个区间内不同的数的个数。

 

不知道为什么主席树卡80分了..

 

感觉问不同数个数的题,都和next或者pre数组有关。

记pre[i]为val[i]上一次出现的位置,第一次出现则为0,我们将询问按右端点升序排序。

对于每个询问,处理出它和上次询问之间新增加的数,具体就是把pre删掉1,cur加上1。

之所以可以这样做,是因为我们只关心在一个区间内,某个数最靠右出现的位置。

 

询问排过序了,记得输出答案也要排序。

#include<algorithm>
#include<iostream>
#include<cstdio>

using namespace std;

inline int rd(){
    int ret=0,f=1;char c;
    while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    return ret*f;
}

const int MAXN=500005;

int n,m;
int val[MAXN];

int t[MAXN<<1];
int query(int x){
    int ret=0;
    for(int i=x;i;i-=i&-i) ret+=t[i];
    return ret;
}
void update(int x,int w){
    if(x==0) return;
    for(int i=x;i<=n;i+=i&-i) t[i]+=w;
}

int pre[MAXN],pos[1000005];

int qx[MAXN],qy[MAXN],id[MAXN],ans[MAXN]; 

bool cmp(int x,int y){return qy[x]<qy[y];}

int main(){
    n=rd();
    for(int i=1;i<=n;i++) {
        val[i]=rd();
    }
    for(int i=1;i<=n;i++){
        pre[i]=pos[val[i]];
        pos[val[i]]=i;
    }
    m=rd();
    for(int i=1;i<=m;i++){
        qx[i]=rd();qy[i]=rd();id[i]=i;
    }
    sort(id+1,id+1+m,cmp);
    int j=1;
    for(int i=1;i<=m;i++){
        int v=id[i];
        for(;j<=qy[v];j++){
            update(pre[j],-1);
            update(j,1);
        }
        ans[v]=query(qy[v])-query(qx[v]-1);
    }
    for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}

 

posted @ 2018-07-27 16:01  GhostCai  阅读(90)  评论(0编辑  收藏  举报