以下总结参考了许多大佬们的博客,开篇先(大佬)%
莫队的入门题目主要为莫队和带修莫队在,这里就先在这里总结一下这两类题目的一些属性。
我认为莫队本质是一种比较优化的暴力查找法。在通过分块操作后把复杂度降低。这个降低的复杂度的大小主要和你分块的方法有着巨大的关系。
普通的莫队,n个元素m个区间询问,他的最佳分块大小为 n/√m ,如果默认n==m的话 复杂度会降到 O(n*√n) 即可以完美运行5X10e5数据。
带修的莫队,多加了一个让指针移动的因子—时间 t ,时间复杂度比较难求,如果设定n,m,t相等的情况下 复杂度O(nlogn+n5/3),同样可以运行50000数据。
贴两道经典的莫队存板子。
P1494 [国家集训队]小Z的袜子 https://www.luogu.org/problemnew/show/P1494
#include<bits/stdc++.h> using namespace std; #define ll long long ll b,ans=0;int l=1,r=0; ll gcd(ll a,ll b) { if(b==0) return a; else return gcd(b,a%b); } struct dd { int x,y,num; }a[50050]; ll cmp(dd x,dd y) { if(x.x/b==y.x/b) return x.y<y.y; else return x.x<y.x; } ll bj[50050]={0}; ll c[50050]; pair<int,int> pr[50050]; void solve(int x,int add) { ans-=bj[c[x]]*bj[c[x]]; //cout<<ans<<endl; bj[c[x]]+=add; ans+=bj[c[x]]*bj[c[x]]; //cout<<ans<<endl; } int main() { ll n,m,q,i,j; scanf("%lld%lld",&n,&q); b=sqrt(n); for(i=1;i<=n;i++) scanf("%lld",&c[i]); for(i=1;i<=q;i++) scanf("%d%d",&a[i].x,&a[i].y),a[i].num=i; sort(a+1,a+q+1,cmp); for(i=1;i<=q;i++) { ll lon=a[i].y-a[i].x+1; //cout<<a[i].x<<" "<<a[i].y<<"lon="<<lon<<endl; while(l<a[i].x) { solve(l,-1);l++; } while(l>a[i].x) { solve(l-1,1);l--; } while(r<a[i].y) { solve(r+1,1);r++; } while(r>a[i].y) { solve(r,-1);r--; } //cout<<l<<" "<<r<<endl; int aans=ans-lon; lon=lon*(lon-1); int gc=gcd(aans,lon); //cout<<ans<<" "<<lon<<endl; if(aans==0) pr[a[i].num].first=0,pr[a[i].num].second=1; else pr[a[i].num].first=aans/gc,pr[a[i].num].second=lon/gc; } for(i=1;i<=q;i++) printf("%d/%d ",pr[i].first,pr[i].second); }
P1903 [国家集训队]数颜色 / 维护队列 https://www.luogu.org/problemnew/show/P1903
#include<bits/stdc++.h> using namespace std; int ans=0;int l=1,r=0,t=0; int b; struct dd { int x,y,t,num; }a[50050]; struct dt { int p, v; }tw[50050]; int cmp(dd x,dd y) { if(x.x/b==y.x/b) { if(x.y/b==y.y/b) return x.t<y.t; return x.y/b<y.y/b; } else return x.x<y.x; } int bj[1000050]={0}; int e=0,tim=0; int c[50050]; int pr[50050]; void solve(int x,int add) { bj[c[x]]+=add; if(bj[c[x]]==0&&add==-1) ans--; if(bj[c[x]]==1&&add==1) ans++; //cout<<ans<<endl; } void time_change(int i,int tt) { if(tw[tt].p>=a[i].x&&tw[tt].p<=a[i].y) { bj[c[tw[tt].p]]--; if(bj[c[tw[tt].p]]==0) ans--; bj[tw[tt].v]++; if(bj[tw[tt].v]==1) ans++; } swap(tw[tt].v,c[tw[tt].p]); } int main() { int n,q,i; char qq[5]; scanf("%d%d",&n,&q); b=pow(n,0.66666); for(i=1;i<=n;i++) scanf("%d",&c[i]); for(i=1;i<=q;i++) { scanf("%s",qq); if(qq[0]=='Q') { e++; scanf("%d%d",&a[e].x,&a[e].y); a[e].t=tim; a[e].num=e; } else { tim++; scanf("%d%d",&tw[tim].p,&tw[tim].v); } } sort(a+1,a+e+1,cmp); for(i=1;i<=e;i++) { //cout<<a[i].x<<" "<<a[i].y<<"lon="<<lon<<endl; while(l<a[i].x) { solve(l,-1);l++; } while(l>a[i].x) { solve(l-1,1);l--; } while(r<a[i].y) { solve(r+1,1);r++; } while(r>a[i].y) { solve(r,-1);r--; } //cout<<l<<" "<<r<<endl; while(t<a[i].t) { time_change(i,t+1); t++; } while(t>a[i].t) { time_change(i,t); t--; } //cout<<ans<<" "<<lon<<endl; pr[a[i].num]=ans; } for(i=1;i<=e;i++) printf("%d ",pr[i]); }