题意:询问你L到R区间右多少种数;
思路:在线应该是可以用主席数树处理的,听说离线的话梳妆数组也可以(不怎么会树状数组这种操作),这里给出的是离线处理的莫队算法(网上好像很多事用一个增加函数,和一个减小函数进行操作的,这里只写了一个函数,偷懒了),莫队的话我觉得hzw学长的博客写的(小z的袜子)比较好,打波广告
代码:(这是SPOJ的代码,BZOJ的代码和这个类似,只是注意数据范围,不然会一直RE)
#include <cstdio> #include <iostream> #include <algorithm> #include <cmath> using namespace std; const int N=3e5+7; int block,cnt[1000007],a[N],res[N],ans; struct node{ int l,r,id; }q[N]; bool cmp(node a,node b) { return a.l/block!=b.l/block?a.l/block<b.l/block:a.r<b.r; } void update(int p,int val) { cnt[a[p]]+=val; if(cnt[a[p]]==1&&val==1)ans++; if(cnt[a[p]]==0&&val==-1)ans--; // printf("fuck %d %d %d ",cnt[a[p]],ans,val); } int main() { int n; scanf("%d",&n); block=sqrt(n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } int m; scanf("%d",&m); for(int i=1;i<=m;i++){ scanf("%d%d",&q[i].l,&q[i].r); q[i].id=i; } sort(q+1,q+1+m,cmp); ans=0; // printf("test "); for(int i=1,l=1,r=0;i<=m;i++){ for(;r<q[i].r;r++) update(r+1,1); for(;r>q[i].r;r--) update(r,-1); for(;l<q[i].l;l++) update(l,-1); for(;l>q[i].l;l--) update(l-1,1); // printf("test %d %d ans === %d ",q[i].l,q[i].r,ans); res[q[i].id]=ans; } for(int i=1;i<=m;i++){ printf("%d ",res[i]); } }