解题报告: luogu P1972
我们首先想到莫队,然后就被卡了。
然后我就不会了。
正解:
对区间内每一个元素最后出现的位置作为有效位置,其他的都是无效位置。
这样我们可以差分了!
我们只需要维护一下每个位置是否是一种颜色的有效位置,对于这个区间内没有的位置,一定是前面有或者是还没出现过,这样的答案是正确的。可以用树状数组维护单点加与前缀和。
最后,按 \(r\) 升序询问就好了。
\(Code:\)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAXN 1000005
int n,m,col[MAXN],pos[MAXN];
int l[MAXN],r[MAXN],lst=0,vis[MAXN]={0},ans[MAXN];
inline int read()
{
int x=0,w=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-') w=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c-'0');c=getchar();};
return x*w;
}
struct tree
{
int t[MAXN];
int lowbit(int x){return x&(-x);}
void add(int x,int y){for(int i=x;i<=n;i+=lowbit(i)) t[i]+=y;}
int query(int x){int ans=0;for(int i=x;i;i-=lowbit(i)) ans+=t[i];return ans;}
}T;
struct node
{
int l,r,id;
}a[MAXN];
bool cmp(node n,node m){return n.r<m.r;}
int main()
{
n=read();
for(int i=1;i<=n;i++) col[i]=read();
m=read();
for(int i=1;i<=m;i++) a[i].l=read(),a[i].r=read(),a[i].id=i,vis[a[i].r]++;
sort(a+1,a+m+1,cmp);
memset(pos,0,sizeof(pos));
for(int i=1;i<=n;i++)
{
if(pos[col[i]]) T.add(pos[col[i]],-1);
T.add(i,1),pos[col[i]]=i;
for(int j=1;j<=vis[i];j++) lst++,ans[a[lst].id]=T.query(a[lst].r)-T.query(a[lst].l-1);
}
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}