大佬的博客
开幕雷击!我既然都贴上了大佬的博客,那还要我有什么用,但是我要是不记录的话早晚会忘,那既然是给自己看的话就象征性地写一下吧,等以后熟练了也不需要这博客了。
莫队虽然用到了分块,但是并不对分块进行操作,而是对分块的性质进行运用。
普通莫队
P1972 [SDOI2009] HH的项链
非常模板的题,但是卡莫队,所以自己去讨论区找双倍经验吧。
莫队是怎么一回事呢,我们把所有的询问都离线地储存下来,然后用 \(l,r\) 指针在数列上移动,在移动的过程中处理答案,在指针移动到查询区间时就储存当前答案,而这个查询区间的选择就很重要了,我们讲每个端点都分到不同的块内,对所属的块进行左端点排序,这样复杂度就降到了 \(O(n\sqrt{n})\)。(我不想证了 其实是不会)
优化
排序奇偶性优化,当查询区间左端点在同一块内,判断所在的块是奇数就按右端点从小到大排序,是偶数就按从大到小排序,这样的话相当于是一个来回,可以很好地节约时间。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+19;int n,m;
int a[N];
int of[N];
int len;
int ans[N];
int cnt[N];
int now=0;
struct ss{int l,r,id;
}q[N];
bool cmp(ss g,ss h){return (of[g.l]^of[h.l])?of[g.l]<of[h.l]:(of[g.l]&1)?g.r<h.r:g.r>h.r;
}
void add(int pos){if(!cnt[a[pos]]++) ++now;
}
signed main(){ios::sync_with_stdio(false);cin>>n>>m;len=sqrt(n);for(int i=1;i<=n;i++){of[i]=(i-1)/len+1;}for(int i=1;i<=n;i++){cin>>a[i];}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); int l=1,r=0;for(int i=1;i<=m;i++){int ql=q[i].l,pr=q[i].r;while(l<ql) now-=!--cnt[a[l++]];while(l>ql) now+=!cnt[a[--l]]++;while(r<pr) now+=!cnt[a[++r]]++;while(r>pr) now-=!--cnt[a[r--]];ans[q[i].id]=now;}for(int i=1;i<=m;i++){cout<<ans[i]<<"\n";}return 0;
}