题目链接:https://www.luogu.com.cn/problem/P1972
这道题要问各区间中有多少个不同的值,由于该题中的数据规模较小,不用离散化(数据规模更大时需要离散化后按该方法做). 我 们此时需要找到一种方法让每个值对于我们查询的贡献只有1,怎么做呢?
考虑这样一个序列:,如果按照简单的桶
来记录i出现的次数,我们即要统计i使得
的数量,一次操作复杂度为
显然效率低下,那我们尝试这样一个记录方法: 另开一个数组让其他位置为0,每个值最后一次出现的位置的值为1,如上述序列对应的
,求出前缀和即为所求.
而对应到原题中,我们不妨将提问的区间以右端点从小到大的顺序依次考虑,设置一个指针表示我们考虑到最右侧的范围. 依次移动指针到每个提问区间的右端点,且每经过一个元素,检验其是否出现过,若没出现过,记录
为其最后出现的位置并将上述提到的数组的
位置的值改为1;若出现过,则需先将数组在其上次出现的位置的值改成0.
该过程用树状数组维护即可.
代码实现:
#include<bits/stdc++.h>
using namespace std;
int const N=1e6+10;
struct qes{
int l,r,id,ans;
}e[N];
inline bool cmp1(qes a,qes b){
if(a.r!=b.r)return a.r<b.r;
return a.l<b.l;
}
inline bool cmp2(qes a,qes b){
return a.id<b.id;
}
int t[N],last[N],n,a[N];
inline int lowbit(int x){
return x&(-x);
}
inline void update(int loc,int val){
for(int i=loc;i<=n;i+=lowbit(i)){
t[i]+=val;
}
}
inline int query(int loc){
int res=0;
for(int i=loc;i>0;i-=lowbit(i)){
res+=t[i];
}
return res;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
int m;cin>>m;
for(int i=1;i<=m;i++){
cin>>e[i].l>>e[i].r;
e[i].id=i;
}
sort(e+1,e+m+1,cmp1);
int cnt=1;
for(int i=1;i<=m;i++){
for(;cnt<=e[i].r;cnt++){
if(last[a[cnt]]){
update(last[a[cnt]],-1);
}
update(cnt,1);
last[a[cnt]]=cnt;
}
e[i].ans=query(e[i].r)-query(e[i].l-1);
}
sort(e+1,e+m+1,cmp2);
for(int i=1;i<=m;i++){
cout<<e[i].ans<<"\n";
}
return 0;
}
1万+

被折叠的 条评论
为什么被折叠?



