题意:给定一个颜色序列,每组询问给出区间[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; }
时间: 2024-10-28 19:11:13