区间种类统计类问题
1. 莫队算法
将询问按照左端点分为sqrt级别块进行排序,然后顺序处理.
例题 小Z的袜子
2. 树状数组
一种很有技巧性的东西
对于一些离线的这类问题,我们可能要统计在一段区间内的种类数,那么我们可以用差分的办法维护前缀和.
具体地说,我们将询问按左端点排序,那么我们就可以从左到右处理了.
看代码比较清楚,好好想一想就懂了.
SDOI HH的项链
#include <cstdio> #include <algorithm> int a[60000],p[60000],bit[60000],n,m,i,j,k,c[2000000]; #define lowbit(x) (x&(-x)) inline int read(){ int x=0;char ch=getchar(); while(ch<'0'||ch>'9'){ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x; } inline void add(int a){ for(;a<=n;a+=lowbit(a)) ++bit[a]; } inline int qry(int a){ int res=0; for(;a;a-=lowbit(a)){ res+=bit[a]; } return res; } inline void cons(){ for(i=1;i<=n;++i){ bit[i]+=a[i]; bit[i+lowbit(i)]+=bit[i]; } } struct query{ int l,r,id; } qrs[300000]; bool cmp(const query& a,const query& b){ return a.l<b.l; } int qrp; int ans[300000]; char s[8000000],pp[15]; int strl,strp; void record(int i){ strp=0; while(i){ j=i/10; pp[strp++]=i-j*10+'0'; i=j; } while(~(--strp)){ s[strl++]=pp[strp]; } s[strl++]='\n'; } int main(){ n=read(); for(i=1;i<=n;++i){ j=read(); if(!c[j]) a[i]=1; c[j]=p[c[j]]=i; } m=read(); for(i=0;i<m;++i) qrs[i].l=read(),qrs[i].r=read(),qrs[i].id=i; std::sort(qrs,qrs+m,cmp); cons(); qrp=0; for(i=1;i<=n;++i){ if(qrs[qrp].l==i){ j=qry(i-1); while(qrs[qrp].l==i&&qrp<m){ ans[qrs[qrp].id]=qry(qrs[qrp].r)-j; ++qrp; } } if(p[i]) add(p[i]); } for(i=0;i<m;++i) record(ans[i]); s[strl-1]='\0'; puts(s); return 0; }
read()函数是读入,record用来输出,add就是树状数组的update,qry就是树状数组的查询,cons从a中构造树状数组.
#include <cstdio> #include <algorithm> int a[1000010],p[1000010],bit[1000010],n,m,i,j,k,c[1000010],q[1000010]; #define lowbit(x) (x&(-x)) inline int read(){ int x=0;char ch=getchar(); while(ch<'0'||ch>'9'){ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x; } inline void add(int a,int p){ for(;a<=n;a+=lowbit(a)) bit[a]+=p; } inline int qry(int a){ int res=0; for(;a;a-=lowbit(a)){ res+=bit[a]; } return res; } inline void cons(){ for(i=1;i<=n;++i){ bit[i]+=a[i]; bit[i+lowbit(i)]+=bit[i]; } } struct query{ int l,r,id; } qrs[1000010]; bool cmp(const query& a,const query& b){ return a.l<b.l; } int qrp; int ans[1000010]; int main(){ n=read(); k=read(); m=read(); for(i=1;i<=n;++i) q[i]=read(); for(i=n;i;--i) p[i]=c[q[i]],c[q[i]]=i; for(i=1;i<=k;++i) if(p[c[i]]) ++a[p[c[i]]]; for(i=0;i<m;++i) qrs[i].l=read(),qrs[i].r=read(),qrs[i].id=i; std::sort(qrs,qrs+m,cmp); cons(); qrp=0; for(i=1;i<=n;++i){ if(qrs[qrp].l==i){ j=qry(i-1); while(qrs[qrp].l==i&&qrp<m){ ans[qrs[qrp].id]=qry(qrs[qrp].r)-j; ++qrp; } } if(p[i]) add(p[i],-1); if(p[p[i]]) add(p[p[i]],1); } for(i=0;i<m;++i) printf("%d\n",ans[i]); return 0; }