莫队

莫队好不容易才学明白,总结一下。

先说问题:在一个长度为n的序列中,每个元素都有一个颜色a[i],一共有m次查询,每次查询给定一个区间,问区间内一共有几种颜色。

再说思路:这道题是典型的莫队题,思路即莫队思路。有左右两个指针,左指针在序列上移动,找寻下个区间的左端点,会改变区间内的颜色,右指针同理。但这样来回移动依然很慢,我们可以将几次查询的区间排序,但以左端点排,右端点依然要来回移动,以右端点排也是这样,我们需要更好的算法,这就需要用到分块算法,首先将序列分块,左端点所在块靠前的排在前面,再在每个块中以右端点由小到大排。最后就是在移动过程中记录颜色种类的多少。并且莫队是离线的,即要先输入完再处理。

下面是莫队板子

#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m,cnt,ge;
int a[100010],tot[100010],ans[100010];
struct node{
    int l,r;
    int id;
}quyu[100010];
bool cmp(node x,node y){
    int qx=x.l/ge,qy=y.l/ge;
    if(qx<qy) return true;
    if(qx==qy&&x.r<y.r) return true;
    return false;
}
void add(int x){
    tot[a[x]]++;
    if(tot[a[x]]==1) cnt++;
}
void del(int x){
    tot[a[x]]--;
    if(tot[a[x]]==0) cnt--;
}
int main(){
    cin>>n>>m;
    ge=sqrt(n);
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=m;i++){
        cin>>quyu[i].l<<quyu[i].r;
        quyu[i].id=i;
    }
    sort(quyu+1,quyu+m+1,cmp);
    int lasl=0,lasr=0;
    for(int i=1;i<=m;i++){
        int ll=quyu[i].l,rr=quyu[i].r;
        while(lasl<ll) del(lasl++);
        while(lasl>ll) add(--lasl);
        while(lasr<rr) add(++lasr);
        while(lasr>rr) del(lasr--);
        ans[quyu[i].id]=cnt;
    }
    for(int i=1;i<=m;i++){
        cout<<ans[i].cnt<<endl;
    }
    return 0;
} 

 

posted @ 2022-02-10 21:09  zzzzzz2  阅读(67)  评论(0编辑  收藏  举报