BZOJ 2738 矩阵乘法 整体二分
题意:
给出n*n的矩阵,求出子矩阵的k小值
分析:
真理:当一个题的题目名是一个算法时,这道题多半和这个算法没啥关系。
其实就是把整体二分的步骤放到二维了。我们需要一个二维线段树来查询操作。
其他嘛,直接把矩阵抻成序列即可。(但要记得记录二维坐标)
代码:
#include<bits/stdc++.h> using namespace std; const int M=505; const int N=60005; int n,m,n2,tot,now; struct node{int x,y,v;}v[M*M]; int q1[N],q2[N],q3[N],q4[N],qk[N]; int ans[N],s[M][M],p[N],q[N],sm[N]; bool cmp(node a,node b){ return a.v<b.v; } void plu(int x,int y,int val){ for(int i=x;i<=n;i+=i&-i) for(int j=y;j<=n;j+=j&-j) {s[i][j]+=val;} return ; } int query(int x,int y){ int r=0;for(int i=x;i;i-=i&-i) for(int j=y;j;j-=j&-j) {r+=s[i][j];}return r; } void solve(int l,int r,int L,int R){ if(l>r) return ; if(L==R){ for(int i=l;i<=r;i++) {ans[p[i]]=v[L].v;}return ; } int mid=(L+R)>>1,md=l-1; while(now<mid) now++, plu(v[now].x,v[now].y,1); while(now>mid) plu(v[now].x,v[now].y,-1),now--; for(int i=l;i<=r;i++){ sm[p[i]]=query(q1[p[i]]-1,q2[p[i]]-1)+ query(q3[p[i]],q4[p[i]])- query(q1[p[i]]-1,q4[p[i]])- query(q3[p[i]],q2[p[i]]-1); if(sm[p[i]]>=qk[p[i]]) md++; } int l1=l,l2=md+1; for(int i=l;i<=r;i++) if(sm[p[i]]>=qk[p[i]]) q[l1++]=p[i]; else q[l2++]=p[i]; for(int i=l;i<=r;i++) p[i]=q[i]; solve(l,md,L,mid);solve(md+1,r,mid+1,R); } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&v[++n2].v),v[n2].x=i,v[n2].y=j; sort(v+1,v+1+n2,cmp); for(int i=1;i<=m;i++) scanf("%d%d%d%d%d",&q1[i],&q2[i],&q3[i], &q4[i],&qk[i]),p[i]=i;solve(1,m,1,n2); for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }