莫队
莫队好不容易才学明白,总结一下。
先说问题:在一个长度为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; }