📅  最后修改于: 2023-12-03 14:58:37.701000             🧑  作者: Mango
本题目为门|门模拟 2017的第53题。其中,题目描述如下:
给出一个长度为n的序列a,以及m个查询。每个查询给定l和r,要求求出[a[l],a[l+1],...,a[r]]中不同数字的个数。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+5;
int a[MAXN],bsize,ans,cnt[MAXN<<5],head,tail,bl[MAXN],to[MAXN],n,m,ba,num[MAXN<<5];
unordered_map<int,int> mp[MAXN];
inline int read(){int a=0,f=1;char ch=getchar();while(ch>'9'||ch<'0'){if(ch=='-')f=-f;ch=getchar();} while(ch>='0'&&ch<='9'){a=a*10+ch-'0';ch=getchar();} return a*f;}
void build(){
bsize = pow(n,0.5),ba=(n-1)/bsize+1;
for (register int i=1;i<=ba;i++){
bl[i] = (i-1)*bsize+1,to[i] = i*bsize;
}
if (to[ba] < n) ba++,bl[ba] = to[ba-1]+1,to[ba] = n;
for (register int i=1;i<=n;i++){
mp[bl[i]][a[i]]++;
if (mp[bl[i]][a[i]] == 1) cnt[bl[i]]++;
}
}
void Check(int pos){
ans += cnt[pos],mp[pos][num[pos]]++;
if (mp[pos][num[pos]]==1) cnt[pos]++;
}
void Run(int pos){
mp[pos][num[pos]]--;
if (!mp[pos][num[pos]]) cnt[pos]--;
ans -= cnt[pos];
}
int main(){
n = read(),m = read();
for (register int i=1;i<=n;i++) a[i] = read();
build();
while (m--){
int l = read(),r = read();
ans = 0;
if (bl[l] == bl[r]){
for (register int i=l;i<=r;i++){
if (!num[bl[l]]) num[bl[l]] = a[i];
if (a[i]!=num[bl[l]]) Check(bl[l]),Run(bl[l]),num[bl[l]] = a[i];
}
printf("%d\n",ans+cnt[bl[l]]);
}else {
for (register int i=l;i<=to[bl[l]];i++){
if (!num[bl[l]]) num[bl[l]] = a[i];
if (a[i]!=num[bl[l]]) Check(bl[l]),Run(bl[l]),num[bl[l]] = a[i];
}
for (register int i=bl[l]+1;i<=bl[r]-1;i++) ans+=cnt[i];
for (register int i=bl[r];i<=r;i++){
if (!num[bl[r]]) num[bl[r]] = a[i];
if (a[i]!=num[bl[r]]) Check(bl[r]),Run(bl[r]),num[bl[r]] = a[i];
}
printf("%d\n",ans+cnt[bl[r]]);
}
}
return 0;
}