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;
}