📜  门|门模拟 2017 |第 53 题(1)

📅  最后修改于: 2023-12-03 14:58:37.701000             🧑  作者: Mango

门|门模拟 2017 |第 53 题

题目简介

本题目为门|门模拟 2017的第53题。其中,题目描述如下:

给出一个长度为n的序列a,以及m个查询。每个查询给定l和r,要求求出[a[l],a[l+1],...,a[r]]中不同数字的个数。

解题思路
  1. 创建一个set或map用于存储区间内出现的不同数字,利用其自带去重的特性解决问题。
  2. 对于每次询问区间[l, r],遍历该区间,将其中的数加入set或map中(即去重),遍历结束后,返回set或map的长度即可。
代码实现
#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;
}
注意事项
  • 本题中常常使用了一些数组的旋转和指针操作,并且使用了STL中的unordered_map容器以及STL中的set容器。
  • 本题中对于边界的判断较为复杂,需要仔细思考。
  • 本文档的代码片段仅包含代码部分,尤其是函数或代码片段之间的关系仅仅是本人个人的理解,读者可根据具体实现情况加以修改,或者在我的项目中找到完整代码。