题解 P1527 【[国家集训队]矩阵乘法】

C3H5ClO

2020-09-14 11:23:44

Solution

发一个$\Theta(n^2\log^2n)$做法。(假设$m$与$n^2$同阶) 首先,这道题空间没法搞树状数组套线段树之类的,只能整体二分。 在整体二分中的某一次分治时,假设值域为$[l,r]$,值域中点为$mid$,则要统计值域在此范围的询问的子矩形中满足$x\in[l,r]$的$x$的个数。由于$cnt(x1,y1,x2,y2)=cnt(0,0,x2,y2)-cnt(0,0,x2,y1-1)-cnt(0,0,x1-1,y2)+cnt(0,0,x1-1,y1-1)$,将一个询问拆成四个询问,这是一个二维偏序问题,并不需要二维树状数组。可以将所有$x\in[l,r]$的$x$看成修改,和询问一起离线下来,按横坐标排序,纵坐标用普通的树状数组解决。这样做,假设这次分治值域区间长度为$l$,询问个数为$q$,则本次分治时间复杂度为$\Theta((l+q)(\log l+\log q))$,算法整体复杂度为$\Theta((n^2+m)(\log n^2+\log m)\log n^2)=\Theta(n^2\log^2n)$。 上代码: ```cpp #include<bits/stdc++.h> using namespace std; const int N=505,M=60005; int n,q,a[N][N],ans[M],x,y,xx,yy,z; int aa[N*N],lenaa,dx[M],o2p[M],o2p1[M],o2p2[M]; struct node{int v,x,y;}o[N*N]; bool operator <(node a,node b){return a.v<b.v;} struct node2{int x1,y1,x2,y2,k,id;}o2[M]; struct node3{int x,y,id;}o3[N*N*2]; bool operator <(node3 a,node3 b){return a.x!=b.x?a.x<b.x:!a.id&&b.id;} int sz[N*N]; void ddxg(int x,int y){for(;x<=lenaa;x+=x&-x)sz[x]+=y;} int qjcx(int x){int y=0; for(;x;x-=x&-x)y+=sz[x]; return y;} void getans(int l,int r,int o2l,int o2r) { if(l==r){for(int i=o2l;i<=o2r;i++)ans[o2[o2p[i]].id]=aa[o[l].v]; return;} int mid=l+r>>1,len1=0,len2=0,len3=0; for(int i=l;i<=mid;i++)o3[++len3]={o[i].x,o[i].y,0}; for(int i=o2l;i<=o2r;i++) { x=o2[o2p[i]].x1; y=o2[o2p[i]].y1; xx=o2[o2p[i]].x2; yy=o2[o2p[i]].y2; o3[++len3]={xx,yy,i}; o3[++len3]={x-1,y-1,i}; o3[++len3]={xx,y-1,-i}; o3[++len3]={x-1,yy,-i}; } sort(o3+1,o3+len3+1); for(int i=1;i<=len3;i++) if(!o3[i].id)ddxg(o3[i].y,1); else if(o3[i].id>0)dx[o3[i].id]+=qjcx(o3[i].y); else dx[-o3[i].id]-=qjcx(o3[i].y); for(int i=o2l;i<=o2r;i++) if(o2[o2p[i]].k<=dx[i])o2p1[++len1]=o2p[i]; else o2[o2p[i]].k-=dx[i],o2p2[++len2]=o2p[i]; for(int i=1;i<=len1;i++)o2p[o2l+i-1]=o2p1[i]; for(int i=1;i<=len2;i++)o2p[o2l+len1+i-1]=o2p2[i]; fill(dx+o2l,dx+o2r+1,0); for(int i=l;i<=mid;i++)ddxg(o[i].y,-1); if(len1)getans(l,mid,o2l,o2l+len1-1); if(len2)getans(mid+1,r,o2l+len1,o2r); } int main() { scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",a[i]+j),aa[++lenaa]=a[i][j]; sort(aa+1,aa+lenaa+1); lenaa=unique(aa+1,aa+lenaa+1)-aa-1; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]=lower_bound(aa+1,aa+lenaa+1,a[i][j])-aa,o[i*n-n+j]={a[i][j],i,j}; sort(o+1,o+n*n+1); for(int i=1;i<=q;i++)scanf("%d%d%d%d%d",&x,&y,&xx,&yy,&z),o2[i]={x,y,xx,yy,z,i},o2p[i]=i; getans(1,n*n,1,q); for(int i=1;i<=q;i++)printf("%d\n",ans[i]); } ```