莫队
莫队就是离线处理一些问题。
当一个问题[l,r]可以由[l-1,r],[l,r+1],[l+1,r],[l,r-1]相差一的区间由O(1)或O(logn)推出时,就可以用莫队莫队实质上是离线处理,通过改变询问的顺序使复杂度降到O(n^1.5)
其实莫队用到分块的地方仅仅是排序中用到?
排序的过程:先计算每个位置应该处于哪个块中,记为pos[i],按(pos[i],r)双关键字排序,然后再对每个区间暴力计算
bzoj2038&&bzoj3781
题解太多了
大概就是个裸的莫队
bzoj2038
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; struct data { ll a,b; int l,r,id; }a[100010]; int n,m; ll tot; int c[100010]; ll cnt[100010],pos[100010]; ll gcd(ll a,ll b) { return b==0?a:gcd(b,a%b); } bool cp1(data x,data y) { if(pos[x.l]!=pos[y.l]) return pos[x.l]<pos[y.l]; return x.r<y.r; } bool cp2(data x,data y) { return x.id<y.id; } void update(int x,int delta) { tot-=cnt[c[x]]*(cnt[c[x]]-1)/2; cnt[c[x]]+=delta; tot+=cnt[c[x]]*(cnt[c[x]]-1)/2; } void solve() { for(int i=1,l=1,r=0;i<=m;i++) { // printf("a[i].l=%d a[i].r=%d\n",a[i].l,a[i].r); while(r<a[i].r) { r++; update(r,1); } while(r>a[i].r) { update(r,-1); r--; } while(l<a[i].l) { update(l,-1); l++; } while(l>a[i].l) { l--; update(l,1); } if(a[i].l==a[i].r) { a[i].a=0; a[i].b=1; continue; } // for(int j=1;j<=n;j++) // { // printf("color[%d]=%d\n",c[j],cnt[c[j]]); // } // printf("l=%d r=%d\n",l,r); // printf("tot=%d\n",tot); a[i].a=tot; a[i].b=(ll)(a[i].r-a[i].l+1)*(ll)(a[i].r-a[i].l)/2; ll k=gcd(a[i].b,a[i].a); a[i].a/=k; a[i].b/=k; if(a[i].a==0) a[i].b=1; } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&c[i]); } int size=(int)(sqrt(n)); for(int i=1;i<=n;i++) { pos[i]=(i-1)/size+1; } for(int i=1;i<=m;i++) { scanf("%d%d",&a[i].l,&a[i].r); a[i].id=i; } sort(a+1,a+m+1,cp1); solve(); sort(a+1,a+m+1,cp2); for(int i=1;i<=m;i++) { printf("%lld/%lld\n",a[i].a,a[i].b); } return 0; }
bzoj3781
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define N 500010 struct data { int l,r,pos,ans; }a[N]; int n,m,k,ans; int cnt[N],c[N],pos[N]; bool cp(data x,data y) { if(pos[x.l]!=pos[y.l]) return pos[x.l]<pos[y.l]; return x.r<y.r; } bool cp1(data x,data y) { return x.pos<y.pos; } void update(int pos,int delta) { ans-=cnt[c[pos]]*cnt[c[pos]]; cnt[c[pos]]+=delta; ans+=cnt[c[pos]]*cnt[c[pos]]; } void solve() { int l=1,r=0; for(int i=1;i<=m;i++) { // printf("a[i].l=%d a[i].r=%d\n",a[i].l,a[i].r); while(l<a[i].l) { update(l,-1); l++; } while(l>a[i].l) { l--; update(l,1); } while(r>a[i].r) { update(r,-1); r--; } while(r<a[i].r) { r++; update(r,1); } a[i].ans=ans; } } int main() { scanf("%d%d%d",&n,&m,&k); int size=(int)(sqrt(n)); for(int i=1;i<=n;i++) { scanf("%d",&c[i]); pos[i]=(i-1)/size+1; } for(int i=1;i<=m;i++) { scanf("%d%d",&a[i].l,&a[i].r); a[i].pos=i; } sort(a+1,a+m+1,cp); solve(); sort(a+1,a+m+1,cp1); for(int i=1;i<=m;i++) { printf("%d\n",a[i].ans); } return 0; }