莫队算法。
https://blog.csdn.net/qq_38891827/article/details/82190013 很多例题
https://blog.csdn.net/qq_41117236/article/details/81453534
https://www.lydsy.com/JudgeOnline/problem.php?id=2038
不带修改的莫队。数区间内有多少个相同的元素。分块大小为n的1/2次方。复杂度为O(n的3/2次方)
#include <bits/stdc++.h> #define ll long long using namespace std; const int maxn=50000+10; int col[maxn],Be[maxn]; ll sum[maxn],ans; struct Mo{ int l,r,ID; ll A,B; }f[maxn]; ll GCD(ll a,ll b){return b==0?a:GCD(b,a%b);} bool cmp(Mo a,Mo b){return Be[a.l]==Be[b.l]?a.r<b.r:a.l<b.l;} bool CMP(Mo a,Mo b){return a.ID<b.ID;} void revise(int x,int add) { ans-=sum[col[x]]*(sum[col[x]]-1); sum[col[x]]+=add; ans+=sum[col[x]]*(sum[col[x]]-1); } int main() { int n,m; scanf("%d%d",&n,&m); int unit=sqrt(n); for(int i=1;i<=n;i++) scanf("%d",&col[i]),Be[i]=i/unit+1; for(int i=1;i<=m;i++) scanf("%d%d",&f[i].l,&f[i].r),f[i].ID=i; sort(f+1,f+m+1,cmp); int l=1,r=0; for(int i=1;i<=m;i++){ while(l<f[i].l) revise(l,-1),l++; while(l>f[i].l) revise(l-1,1),l--; while(r<f[i].r) revise(r+1,1),r++; while(r>f[i].r) revise(r,-1),r--; if(f[i].l==f[i].r){ f[i].A=0; f[i].B=1; continue; } f[i].A=ans; f[i].B=1LL*(f[i].r-f[i].l+1)*(f[i].r-f[i].l); //分母:len*(len-1) ll gcd=GCD(f[i].A,f[i].B); f[i].A/=gcd; f[i].B/=gcd; } sort(f+1,f+m+1,CMP); for(int i=1;i<=m;i++) printf("%lld/%lld\n",f[i].A,f[i].B); return 0; }
https://www.lydsy.com/JudgeOnline/problem.php?id=2120
待修改的莫队,分块大小为n的2/3次方,时间复杂度为O(n的5/3次方)
#include <bits/stdc++.h> using namespace std; const int maxn=10000+10; struct Query{ int l,r,Tim,ID; }q[maxn]; struct Change{ int pos,New,Old; }c[maxn]; int s[maxn],Be[maxn]; int now[maxn],ans[maxn]; int color[maxn*100]; int Ans,l=1,r; bool cmp(Query a,Query b) { return Be[a.l]==Be[b.l]?(Be[a.r]==Be[b.r]?a.Tim<b.Tim:a.r<b.r):a.l<b.l; } void revise(int x,int d) { color[x]+=d; if(d>0) Ans+=color[x]==1; if(d<0) Ans-=color[x]==0; } void going(int x,int d) { if(l<=x&&x<=r) revise(d,1),revise(s[x],-1); s[x]=d; } int main() { int n,m; scanf("%d%d",&n,&m); int unit=pow(n,2.0/3); for(int i=1;i<=n;i++){ scanf("%d",&s[i]); now[i]=s[i]; Be[i]=i/unit+1; //分块 } int Time=0,t=0; while(m--){ char sign; int x,y; scanf(" %c %d%d",&sign,&x,&y); if(sign=='Q') q[++t]=(Query){x,y,Time,t}; else c[++Time]=(Change){x,y,now[x]},now[x]=y; } sort(q+1,q+t+1,cmp); int T=0; for(int i=1;i<=t;i++){ while(T<q[i].Tim) going(c[T+1].pos,c[T+1].New),T++; while(T>q[i].Tim) going(c[T].pos,c[T].Old),T--; while(l<q[i].l) revise(s[l],-1),l++; while(l>q[i].l) revise(s[l-1],1),l--; while(r<q[i].r) revise(s[r+1],1),r++; while(r>q[i].r) revise(s[r],-1),r--; ans[q[i].ID]=Ans; } for(int i=1;i<=t;i++) printf("%d\n",ans[i]); return 0; }