首页 > 代码库 > BZOJ1878 SDOI2009 HH的项链 树状数组

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

 

BZOJ1878 SDOI2009 HH的项链 树状数组