Two-dimensional Mo's algorithm, as the name suggests, means each state can be expanded in four directions.
In two-dimensional Mo's algorithm, each pointer movement involves operating on a row or a column of numbers. The specific implementation is similar to the ordinary one-dimensional Mo's algorithm and will not be repeated here. This section focuses on selecting the block size.
Block Size Selection
Let the number of queries be \(q\), the coordinates of the top-left corner of the current matrix be \((x_1,\ y_1)\), the coordinates of the bottom-right corner be \((x_2,\ y_2)\), and the block size be \(B\).
Thus, we only need to set \(q\cdot B=n^4\cdot B^{-3}\), i.e., \(B=n\cdot q^{-\frac 14}\).
Note that the computed \(B\)may be \(0\), so special handling is required.
Finally, the time complexity of the computation part is \(\Theta(n^2\cdot q^{\frac 34})\), and adding the sorting process for queries, the total time complexity is \(\Theta(n^2\cdot q^{\frac 34}+q\log q)\).
Input an \(n\times m\) matrix, where each element of the matrix is an integer. There are \(q\) queries, each asking for the weight of a submatrix. The weight of the matrix is defined as follows: for an integer \(x\), if it appears \(p\) times in the matrix, it contributes \(p^2\) to the weight of the matrix.
Data range: \(1\leq n,\ m\leq 200\), \(0\leq q\leq 10^5\), \(|\) matrix element value \(| \leq 2\times 10^9\).
Solution Idea
First, discretize the values. During the two-dimensional Mo's algorithm, use an array to record the current occurrence count of each number.
#include<algorithm>#include<cmath>#include<iostream>usingnamespacestd;intn,m,q,a[201][201];longlongans[100001];intdisc[250001],cntdisc;// For discretizationintblocklen,counts[40001];longlongnow;structQuestion{intx1,y1,x2,y2,qid;booloperator<(Questiontmp)const{if(x1/blocklen!=tmp.x1/blocklen)returnx1<tmp.x1;if(y1/blocklen!=tmp.y1/blocklen)returny1<tmp.y1;if(x2/blocklen!=tmp.x2/blocklen)returnx2<tmp.x2;returny2<tmp.y2;}}Q[100001];intQcnt;voidmo_algo_row(intid,intval,intY1,intY2){for(inti=Y1;i<=Y2;i++)now-=(longlong)counts[a[id][i]]*counts[a[id][i]],counts[a[id][i]]+=val,now+=(longlong)counts[a[id][i]]*counts[a[id][i]];}voidmo_algo_column(intid,intval,intX1,intX2){for(inti=X1;i<=X2;i++)now-=(longlong)counts[a[i][id]]*counts[a[i][id]],counts[a[i][id]]+=val,now+=(longlong)counts[a[i][id]]*counts[a[i][id]];}voidmo_algo(){blocklen=pow(n*m,0.5)/pow(q,0.25);if(blocklen<1)blocklen=1;sort(Q+1,Q+1+Qcnt);intX1=1,Y1=1,X2=0,Y2=0;for(inti=1;i<=Qcnt;i++){while(X1>Q[i].x1)mo_algo_row(--X1,1,Y1,Y2);while(X2<Q[i].x2)mo_algo_row(++X2,1,Y1,Y2);while(Y1>Q[i].y1)mo_algo_column(--Y1,1,X1,X2);while(Y2<Q[i].y2)mo_algo_column(++Y2,1,X1,X2);while(X1<Q[i].x1)mo_algo_row(X1++,-1,Y1,Y2);while(X2>Q[i].x2)mo_algo_row(X2--,-1,Y1,Y2);while(Y1<Q[i].y1)mo_algo_column(Y1++,-1,X1,X2);while(Y2>Q[i].y2)mo_algo_column(Y2--,-1,X1,X2);ans[Q[i].qid]=now;}}intmain(){cin.tie(nullptr)->sync_with_stdio(false);cin>>n>>m;for(inti=1;i<=n;i++)for(intj=1;j<=m;j++)cin>>a[i][j],disc[++cntdisc]=a[i][j];sort(disc+1,disc+1+cntdisc);cntdisc=unique(disc+1,disc+cntdisc+1)-disc-1;for(inti=1;i<=n;i++)for(intj=1;j<=m;j++)a[i][j]=lower_bound(disc+1,disc+1+cntdisc,a[i][j])-disc;cin>>q;for(inti=1;i<=q;i++){intx1,y1,x2,y2;cin>>x1>>y1>>x2>>y2;if(x1>x2)swap(x1,x2);if(y1>y2)swap(y1,y2);Q[++Qcnt]={x1,y1,x2,y2,i};}mo_algo();for(inti=1;i<=q;++i)cout<<ans[i]<<'\n';return0;}
First, similar to the previous problem, the entire matrix needs to be discretized. However, note that in addition to partitioning the values, the value range of the numbers also needs to be partitioned to compute the answer.
For this problem, the time limit is not very lenient, so pay attention to code constant optimization. The computed block size is generally small; when \(n\) and \(q\) are at their maximum values, the block size is approximately \(11\). It can be set as a constant to save code execution time.
#include<algorithm>#include<iostream>#include<vector>usingnamespacestd;intn,q,a[501][501],ans[60001];intdisc[250001],cntdisc;// For discretizationintnn;intblockId[501],blocklen;// Block decompositionintrangeblockId[250001],rangeblocklen;// Value range block decompositionintcounts[250001],countsum[501];// Frequency of each value and block sumstructPosition{intx,y;};vector<Position>pos[250001];structQuestion{intx1,y1,x2,y2,k,qid;booloperator<(Questiontmp)const{if(blockId[x1]!=blockId[tmp.x1])returnblockId[x1]<blockId[tmp.x1];if(blockId[y1]!=blockId[tmp.y1])returnblockId[x1]&1?y1<tmp.y1:y1>tmp.y1;if(blockId[y2]!=blockId[tmp.y2])returnblockId[y1]&1?y2<tmp.y2:y2>tmp.y2;elsereturnblockId[y2]&1?x2<tmp.x2:x2>tmp.x2;}}Q[60001];intQcnt;voidmo_algo(){blocklen=11;for(inti=1;i<=n;++i)blockId[i]=(i-1)/blocklen+1;rangeblocklen=n+1;for(inti=1;i<=nn;++i)rangeblockId[i]=(i-1)/rangeblocklen+1;counts[a[1][1]]=countsum[rangeblockId[a[1][1]]]=1;sort(Q+1,Q+1+Qcnt);intL=1,R=1,D=1,U=1;for(inti=1;i<=q;++i){while(R<Q[i].y2){++R;for(inti=U;i<=D;++i)++counts[a[i][R]],++countsum[rangeblockId[a[i][R]]];}while(L>Q[i].y1){--L;for(inti=U;i<=D;++i)++counts[a[i][L]],++countsum[rangeblockId[a[i][L]]];}while(D<Q[i].x2){++D;for(inti=L;i<=R;++i)++counts[a[D][i]],++countsum[rangeblockId[a[D][i]]];}while(U>Q[i].x1){--U;for(inti=L;i<=R;++i)++counts[a[U][i]],++countsum[rangeblockId[a[U][i]]];}while(R>Q[i].y2){for(inti=U;i<=D;++i)--counts[a[i][R]],--countsum[rangeblockId[a[i][R]]];--R;}while(L<Q[i].y1){for(inti=U;i<=D;++i)--counts[a[i][L]],--countsum[rangeblockId[a[i][L]]];++L;}while(D>Q[i].x2){for(inti=L;i<=R;++i)--counts[a[D][i]],--countsum[rangeblockId[a[D][i]]];--D;}while(U<Q[i].x1){for(inti=L;i<=R;++i)--counts[a[U][i]],--countsum[rangeblockId[a[U][i]]];++U;}intres=1,cnt=0;while(cnt+countsum[res]<Q[i].k&&res<=rangeblockId[nn])cnt+=countsum[res],++res;res=(res-1)*rangeblocklen+1;while(cnt+counts[res]<Q[i].k&&res<=nn)cnt+=counts[res],++res;ans[Q[i].qid]=disc[res];}}intmain(){cin.tie(nullptr)->sync_with_stdio(false);cin>>n>>q;nn=n*n;for(inti=1;i<=n;++i)for(intj=1;j<=n;++j){intx;cin>>x;a[i][j]=disc[++cntdisc]=x;}sort(disc+1,disc+1+cntdisc);cntdisc=unique(disc+1,disc+cntdisc+1)-disc-1;for(inti=1;i<=n;++i)for(intj=1;j<=n;++j)a[i][j]=lower_bound(disc+1,disc+1+cntdisc,a[i][j])-disc;for(inti=1;i<=q;++i){intx1,y1,x2,y2,k;cin>>x1>>y1>>x2>>y2>>k;Q[++Qcnt]={x1,y1,x2,y2,k,i};}mo_algo();for(inti=1;i<=q;++i)cout<<ans[i]<<'\n';return0;}