BZOJ1878 SDOI2009 HH的项链 树状数组

题意:给定一个颜色序列,每组询问给出区间[l,r],求[l,r]中不同颜色的数量

题解:

首先把所有颜色离散化,然后离线,将询问按右区间升序排列。从1-N把整个序列扫一遍,设Pos[i]为第i个颜色最后出现的位置,假定当前扫到的位置为i,则更新Pos[a[i]],那么问题变成了:求一个序列(Pos)中,大于等于一个数(L)的数的数量。

用树状数组维护Pos=j的数的数量,每次查询树状数组中L-N的和即可。

貌似SDOI不喜欢考大型数据结构啊……坐等今年打脸

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
#define lowbit(x) (x&(-x))

const int MAXN=50000+2;
const int MAXM=200000+2;
struct Hash{
    int u,t;
    Hash *Next;
    Hash(){}
    Hash(int _u,int _t,Hash *_Next):u(_u),t(_t),Next(_Next){}
}*Tab[MAXN],mem[MAXM];
int N,M,a[MAXN],cnt,Ans[MAXM],Pos[MAXN],s[MAXN];
map<int,int> m;

void Update(int p,int x){
    while(p<=N) s[p]+=x,p+=lowbit(p);
}

int Sum(int p){
    int Ret=0;
    while(p) Ret+=s[p],p-=lowbit(p);
    return Ret;
}

int main(){
    scanf("%d",&N);
    for(int i=1;i<=N;i++){
        scanf("%d",a+i);
        if(!m[a[i]]) m[a[i]]=++cnt;
        a[i]=m[a[i]];
    }
    scanf("%d",&M),cnt=0;
    for(int i=1,l,r;i<=M;i++){
        scanf("%d %d",&l,&r);
        mem[cnt].u=l,mem[cnt].t=i,mem[cnt].Next=Tab[r],Tab[r]=&mem[cnt],cnt++;
    }

    for(int i=1;i<=N;i++){
        if(Pos[a[i]]) Update(Pos[a[i]],-1);
        Pos[a[i]]=i,Update(i,1);
        for(Hash *p=Tab[i];p;p=p->Next) Ans[p->t]=Sum(N)-Sum(p->u-1);
    }
    for(int i=1;i<=M;i++) printf("%d\n",Ans[i]);

    return 0;
}
View Code

 

posted @ 2017-03-04 17:53  WDZRMPCBIT  阅读(117)  评论(0编辑  收藏  举报