题目描述
HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答……因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。
输入输出格式
输入格式:
第一行:一个整数N,表示项链的长度。
第二行:N 个整数,表示依次表示项链中贝壳的编号(编号为0 到1000000 之间的整数)。
第三行:一个整数M,表示HH 询问的个数。
接下来M 行:每行两个整数,L 和R(1 ≤ L ≤ R ≤ N),表示询问的区间。
输出格式:
M 行,每行一个整数,依次表示询问对应的答案。
输入输出样例
输入样例#1:
6
1 2 3 4 3 5
3
1 2
3 5
2 6
输出样例#1:
2
2
4
说明
数据范围:
对于100%的数据,N <= 500000,M <= 500000。
解释:1.莫队搞一下,按照块排序呢,最后在块里进行暴力,2可持续化线段树,维护从开头到结尾的求和线段树,值为维护last[i],i号节点相同的值最近出现的位置,然后我们对应区间找到相应的线段树再做查就好了。3.数状数组,我们按照右端点排序,然后维护最右端某点的贡献位置,如果前面出现相同的则去掉。最后区间求和就OK
//莫队
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
struct xxx{
int l,r,block,id;
}q[200001];
int a[50001],cnt[1000100],ans[200001];
bool cmp(xxx a,xxx b){if(a.block!=b.block)return a.block<b.block;return a.r<b.r;}
int main()
{
int n,m;scanf("%d",&n);int T=(int)sqrt((double)n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);q[i].block=(q[i].l+1)/T;q[i].id=i;
}
sort(q+1,q+m+1,cmp);
int l=1,r=0,sum=0;
for(int i=1;i<=m;i++){
while(r<q[i].r){cnt[a[++r]]++;if(cnt[a[r]]==1)sum++;}
while(r>q[i].r){cnt[a[r]]--;if(cnt[a[r--]]==0)sum--;}
while(l<q[i].l){cnt[a[l]]--;if(cnt[a[l++]]==0)sum--;}
while(l>q[i].l){cnt[a[--l]]++;if(cnt[a[l]]==1)sum++;}
ans[q[i].id]=sum;
}
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}
//类似树状数组的可持续化线段树
// It is made by XZZ
#include<cstdio>
#include<algorithm>
#define il inline
#define rg register
#define vd void
#define sta static
typedef long long ll;
il int gi(){
rg int x=0,f=1;rg char ch=getchar();
while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int maxn=50011;
int n;
namespace BITSegtree{
#define mid ((l+r)>>1)
int rt[maxn],ls[maxn*100],rs[maxn*100],sum[maxn*100],index;
il vd _update(int&x,int l,int r,const int&p,const int&k){
if(!x)x=++index;sum[x]+=k;if(l==r)return;
if(p<=mid)_update(ls[x],l,mid,p,k);
else _update(rs[x],mid+1,r,p,k);
}
il int _query(int x,int l,int r,const int&L,const int&R){
if( !x || r<L || R<l )return 0;if( L<=l && r<=R )return sum[x];
return _query(ls[x],l,mid,L,R)+_query(rs[x],mid+1,r,L,R);
}
il int lb(const int&x){return x&-x;}
il vd Update(int x,int y){while(x<=n)_update(rt[x],1,n+1,y+1,1),x+=lb(x);}
il int Query(int l,int r,int x,int y){
sta int ret;ret=0;
while(r)ret+=_query(rt[r],1,n+1,x+1,y+1),r-=lb(r);
--l;while(l)ret-=_query(rt[l],1,n+1,x+1,y+1),l-=lb(l);
return ret;
}
}
int lst[1001001];
int main(){
//freopen("diff.in","r",stdin);
//freopen("diff.out","w",stdout);
using namespace BITSegtree;
n=gi();int k;
for(rg int i=1;i<=n;++i)k=gi(),Update(i,lst[k]),lst[k]=i;
int l,r,m=gi();
while(m--)l=gi(),r=gi(),printf("%d\n",Query(l,r,0,l-1));
return 0;
}
//树状数组解法
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define lowbit(x) x&(-x)
using namespace std;
#define maxn 1000119
int num[maxn],tree[maxn],booll[maxn],nnn[maxn],N,ww;;
struct tt{
int l,r;
int pos;
};
tt ask[maxn];
bool cmp(tt x,tt y){
return x.r<y.r;
}
void add(int n,int now){
while(n<=N){
tree[n]+=now;
n+=lowbit(n);
}
}
int sum(int n){
int ans=0;
while(n!=0){
ans+=tree[n];
n-=lowbit(n);
}
return ans;
}
int main(){
scanf("%d",&N);
for(int i=1;i<=N;i++)
scanf("%d",&num[i]);
scanf("%d",&ww);
for(int i=1;i<=ww;i++){
scanf("%d%d",&ask[i].l,&ask[i].r);
ask[i].pos=i;
}
sort(ask+1,ask+1+ww,cmp);
int next=1;
for(int i=1;i<=ww;i++){
for(int j=next;j<=ask[i].r;j++){
if(booll[num[j]])
add(booll[num[j]],-1);
add(j,1);
booll[num[j]]=j;
}
next=ask[i].r+1;
nnn[ask[i].pos]=sum(ask[i].r)-sum(ask[i].l-1);
}
for(int i=1;i<=ww;i++)
cout<<nnn[i]<<endl;
return 0;
}