莫队是一个优美的暴力
当我们可以在 O(1) 时间推到 L[i-1], L[i+1] , R[i-1] , R[i+1] 的时候 ,就可以使用莫队来解决这个问题啦
一 普通莫队
首先分块,将询问的区间按照左端点所处的块来排序,然后按顺序处理每一个询问就好了
这里有一个小 trick ,排序的时候可以按照块的奇偶性来排序,可以大大的提高效率,虽然我并不知道为什么。
经典例题: 小Z的袜子
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cmath> #include<stack> #include<queue> using namespace std; typedef long long ll; const int maxn = 100010; int n,m,blo; int l=1,r=0; int c[maxn],cnt[maxn],pos[maxn]; ll res=0; struct Q{ int l,r,id; }q[maxn]; struct Ans{ ll a,b; }ans[maxn]; bool cmp(Q a,Q b){ if(pos[a.l]==pos[b.l]) return a.r<b.r; return a.l<b.l; } void add(int i){ res-=1ll*cnt[c[i]]*cnt[c[i]]; ++cnt[c[i]]; res+=1ll*cnt[c[i]]*cnt[c[i]]; } void del(int i){ res-=1ll*cnt[c[i]]*cnt[c[i]]; --cnt[c[i]]; res+=1ll*cnt[c[i]]*cnt[c[i]]; } ll gcd(ll a,ll b){ if(a<b) swap(a,b); return b==0?a:gcd(b,a%b); } ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } int main(){ n=read(),m=read(); blo=sqrt(n); for(int i=1;i<=n;i++) c[i]=read(),pos[i]=(i-1)/blo+1; for(int i=1;i<=m;i++){ q[i].l=read(),q[i].r=read(); q[i].id=i; } sort(q+1,q+1+m,cmp); for(int i=1;i<=m;i++){ while(l<q[i].l){ del(l); l++; } while(l>q[i].l){ add(l-1); l--; } while(r<q[i].r){ add(r+1); r++; } while(r>q[i].r){ del(r); r--; } if(q[i].l==q[i].r){ ans[q[i].id]=(Ans){0,1}; continue; } ans[q[i].id]=(Ans){res-(r-l+1),1ll*(r-l+1)*(r-l)}; } for(int i=1;i<=m;i++){ ll g=gcd(ans[i].a,ans[i].b); printf("%lld/%lld\n",ans[i].a/g,ans[i].b/g); } return 0; }