莫队

  • 分块:将整个数列按照一定的块大小进行划分,一般块的大小为 \(\sqrt{n}\),其中\(n\)是数列的长度。这样可以将数列分成若干个小块,每个小块内部的元素具有一定的连续性。
  • 排序查询区间:对于给定的多个查询区间,按照一定的规则进行排序。通常的排序规则是先按照左端点所在的块进行排序,如果左端点在同一个块内,则按照右端点进行排序。这种排序方式可以使得在处理查询时,相邻的查询区间之间的转移更加高效。
  • 区间转移:在处理每个查询区间时,根据当前已经处理过的区间和待处理的区间之间的差异,通过适当的操作来更新统计信息。当从区间转移到时,只需要增加或减少元素对统计结果的影响。

板子

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
struct node
{
    int id,l,r;
}q[N];
int n,m;
int cnt[N],sum;
int a[N],ans[N];
bool cmp(node A,node B)
{
    if(A.l/sqrt(n)!=B.l/sqrt(N))
        return A.l<B.l;
    return A.r<B.r;
}
void add(int x)
{
    if(!cnt[x]) sum++;
    cnt[x]++;
}
void del(int x)
{
    cnt[x]--;
    if(!cnt[x]) sum--;
}
int main()
{
    /*...*/
    for(int i=1;i<=m;i++)
    {
        cin>>q[i].l>>q[i].r;
        q[i].id=i;
    }
    sort(q+1,q+1+m,cmp);
    for(int i=1,l=1,r=0;i<=m;++i){
        while(l>q[i].l) add(a[--l]);//左扩展
        while(r<q[i].r) add(a[++r]);//右扩展
        while(l<q[i].l) del(a[l++]);//左删除
        while(r>q[i].r) del(a[r--]);//右删除
        ans[q[i].id]=sum;
      }
    return 0;
}
posted @ 2025-02-28 09:46  流氓兔LMT  阅读(14)  评论(0)    收藏  举报