"Introduction to Algorithms"
MO team algorithm is used for off-line processing of processing interval problem of a class of algorithms, very easy to understand and get started, the application surface is very wide, and even can be operated on the tree.
When we get $[l,r]$ 's answer, we can use the $[l-1,r],[l+1,r],[l,r-1],[l,r+1]$ algorithm if we can extend the answer with a lower complexity, usually the complexity of this extension is $o (1) $ or $o (LOGN) $.
If we move the left and right endpoints for every inquiry, then the complexity must be $o (n^2) $, and the essence of the MO team algorithm is to combine the idea of chunking.
The complexity of the extension once is $o (f (n)) $. The sequence is divided into $\sqrt{n}$ blocks, the query is sorted, the left end block number is the first keyword, the right end is the second keyword, so expand, for each query, the complexity of the left endpoint extension is $o (\sqrt{n}*f (n)) $, and for the left end of each block, The complexity of the right endpoint extension is $o (n*f (n)) $, and you can see that the complexity of the right endpoint extension is independent of the number of queries, so the total complexity is $o ((n+m) *\sqrt{n}*f (n)) $.
There is a constant optimization is left endpoint in odd block words right endpoint ascending sort, in even block words right endpoint descending sort, because this is equivalent to a right endpoint to run back and forth process, can save many times the right end of the extension, can have a significant efficiency improvement.
"Algorithmic Flow"
The query is sorted.
Sweep through the query, from the left and right end of the last query to the current query, to arrive at the answer.
BOOL operator<(Poi A, poi b) {returnBL[A.L]<BL[B.L] | | (BL[A.L]==BL[B.L] && (bl[a.l]&1)?a.r<b.r:a.r>B.R));} InlinevoidUpdateintXintDelta) {...//Update Information}intMain () {read (n); read (m);intblo=sqrt (n); for(intI=1; i<=n;i++) read (A[i]); for(intI=1; i<=m;i++) Read (Q[I].L), read (Q[I].R), q[i].pos=i; for(intI=1; i<=n;i++) bl[i]= (i-1)/blo+1; Sort (q+1, q+1+m); for(intI=1, l=1, r=0; i<=m;i++) { while(L<Q[I].L) Update (l++,-1); while(L>Q[I].L) Update (--L,1); while(R<Q[I].R) Update (++R,1); while(R>Q[I].R) Update (R--,-1); ...//Update Answer }}
View Code
Examples
Example 1:bzoj2038: [2009 countries Training team] small Z socks (hose)
Naked problem, to find the interval of each color occurrence, and then casually calculate the contribution can be.
#include <iostream>#include<cstring>#include<cstdlib>#include<cstdio>#include<cmath>#include<algorithm>#definell Long Longusing namespacestd;Const intmaxn=500010, inf=1e9;structpoi{intL, R, POS;} Q[MAXN];intN, M;intA[MAXN], BL[MAXN], cnt[maxn];ll FZ, ANSFZ[MAXN], Ansfm[maxn];inlinevoidReadint&k) { intf=1; k=0;CharC=GetChar (); while(c<'0'|| C>'9') c=='-'&& (f=-1), c=GetChar (); while(c<='9'&& c>='0') k=k*Ten+c-'0', c=GetChar (); K*=F;}BOOL operator<(Poi A, poi b) {returnBL[A.L]<BL[B.L] | | (BL[A.L]==BL[B.L] && (bl[a.l]&1)?a.r<b.r:a.r>B.R));} InlinevoidUpdateintXintDelta) {FZ-=1ll*cnt[a[x]]* (cnt[a[x]]-1); CNT[A[X]]+=Delta; FZ+=1ll*cnt[a[x]]* (cnt[a[x]]-1);} ll GCD (ll A, ll b) {returnB?GCD (b, a%b): A;} intMain () {read (n); read (m);intblo=sqrt (n); for(intI=1; i<=n;i++) read (A[i]); for(intI=1; i<=m;i++) Read (Q[I].L), read (Q[I].R), q[i].pos=i; for(intI=1; i<=n;i++) bl[i]= (i-1)/blo+1; Sort (q+1, q+1+m); for(intI=1, l=1, r=0; i<=m;i++) { while(L<Q[I].L) Update (l++,-1); while(L>Q[I].L) Update (--L,1); while(R<Q[I].R) Update (++R,1); while(R>Q[I].R) Update (R--,-1); intlen=q[i].r-q[i].l+1; intD=GCD (FZ, 1ll*len* (len-1)); Ansfz[q[i].pos]=fz/d; ansfm[q[i].pos]=1ll*len* (len-1)/D; } for(intI=1; i<=m;i++) printf ("%lld/%lld\n", Ansfz[i], Ansfm[i]?ansfm[i]:1);}
View Code
Example 2:bzoj[ahoi2013] Job
Add a weighted tree array to maintain the number of occurrences and types of each weight.
#include <iostream>#include<cstring>#include<cstdlib>#include<cstdio>#include<cmath>#include<algorithm>using namespacestd;Const intmaxn=1000010, inf=1e9;structpoi{intL, R, a, B, pos;} Q[MAXN];intN, M;intA[MAXN], BL[MAXN], tree[2][MAXN], ANS1[MAXN], ANS2[MAXN], Cnt[maxn];inlinevoidReadint&k) { intf=1; k=0;CharC=GetChar (); while(c<'0'|| C>'9') c=='-'&& (f=-1), c=GetChar (); while(c<='9'&& c>='0') k=k*Ten+c-'0', c=GetChar (); K*=F;}BOOL operator<(Poi A, poi b) {returnBL[A.L]<BL[B.L] | | (BL[A.L]==BL[B.L] && (bl[a.l]&1)?a.r<b.r:a.r>B.R));} InlinevoidAddintTyintXintDelta) { for(; x<=n;x+=x&-x) tree[ty][x]+=Delta;} InlineintQueryintTyintx) {intsum=0; for(; x;x-=x&-x) sum+=tree[ty][x];returnsum;} InlinevoidUpdateintXintDelta) {Add (0, A[x], delta); if(!cnt[a[x]] && delta==1) Add (1, A[x],1); CNT[A[X]]+=Delta; if(!cnt[a[x]] && delta==-1) Add (1, A[x],-1); }intMain () {read (n); read (m);intblo=sqrt (n); for(intI=1; i<=n;i++) bl[i]= (i-1)/blo+1; for(intI=1; i<=n;i++) read (A[i]); for(intI=1; i<=m;i++) Read (Q[I].L), read (Q[I].R), read (Q[I].A), read (q[i].b), q[i].pos=i; Sort (q+1, q+1+m); for(intI=1, l=1, r=0; i<=m;i++) { while(L<Q[I].L) Update (l++,-1); while(L>Q[I].L) Update (--L,1); while(R<Q[I].R) Update (++R,1); while(R>Q[I].R) Update (R--,-1); Ans1[q[i].pos]=query (0, q[i].b)-query (0, q[i].a-1); Ans2[q[i].pos]=query (1, q[i].b)-query (1, q[i].a-1); } for(intI=1; i<=m;i++) printf ("%d%d\n", Ans1[i], ans2[i]);}
View Code
Example 3
Preliminary study on "algorithm" MO team algorithm