矩阵乘法
题目描述
给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数。
输入输出格式
输入格式:
第一行两个数N,Q,表示矩阵大小和询问组数;
接下来N行N列一共N*N个数,表示这个矩阵;
再接下来Q行每行5个数描述一个询问:x1,y1,x2,y2,k表示找到以(x1,y1)为左上角、以(x2,y2)为右下角的子矩形中的第K小数。
输出格式:
对于每组询问输出第K小的数。
输入输出样例
说明
矩阵中数字是10^9以内的非负整数;
20%的数据:N<=100,Q<=1000;
40%的数据:N<=300,Q<=10000;
60%的数据:N<=400,Q<=30000;
100%的数据:N<=500,Q<=60000。
分析:
是的,这道题虽然叫矩阵乘法,但是和矩阵乘法一点关系都没有。
求矩阵$k$小就能想到用整体二分,不过因为是二维,所以需要用二维树状数组,然后写法需要漂亮一点,因为这题有点卡常。
另外,有一点需要讲一下,平常我写树状数组都是这样的:
inline void add(int pos,int x) { for(; pos<=n; pos+=lowbit(pos)) c[pos]+=x; }
但是在二维树状数组中就不能这么写,应该写成:
inline void add(int x,int y,int v) { for(int i=x; i<=n; i+=lowbit(i)) for(int j=y; j<=n; j+=lowbit(j)) c[i][j]+=v; }
Code:
//It is made by HolseLee on 6th Oct 2018 //Luogu.org P1527 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N=4e5+7; int n,m,cnt,c[505][505],q1[N],q2[N],id[N],ans[N]; struct Node { int x,y,v; Node() {} Node(const int _x,const int _y,const int _v): x(_x), y(_y), v(_v) {} bool operator < (const Node a) const { return v < a.v; } }a[N]; struct Qus { int x1,y1,x2,y2,k; }q[N]; inline int read() { char ch=getchar(); int num =0; bool flag=false; while( ch<'0' || ch>'9' ) { if( ch=='-' ) flag=true; ch=getchar(); } while( ch>='0' && ch<='9' ) { num=num*10+ch-'0'; ch=getchar(); } return flag ? -num : num; } inline int lowbit(int x) { return x&(-x); } inline void add(int x,int y,int v) { for(int i=x; i<=n; i+=lowbit(i)) for(int j=y; j<=n; j+=lowbit(j)) c[i][j]+=v; } inline int quary(int x,int y) { int ret=0; for(int i=x; i; i-=lowbit(i)) for(int j=y; j; j-=lowbit(j)) ret+=c[i][j]; return ret; } inline int get(int x1,int y1,int x2,int y2) { return quary(x2,y2)-quary(x1-1,y2)-quary(x2,y1-1)+quary(x1-1,y1-1); } void solve(int l,int r,int L,int R) { if( l>r || L>R ) return; if( l==r ) { for(int i=L; i<=R; ++i) ans[id[i]]=a[l].v; return; } int mid=(l+r)>>1, cnt1=0, cnt2=0; for(int i=l; i<=mid; ++i) add(a[i].x,a[i].y,1); for(int i=L; i<=R; ++i) { int tmp=get(q[id[i]].x1,q[id[i]].y1,q[id[i]].x2,q[id[i]].y2); if( tmp>=q[id[i]].k ) q1[++cnt1]=id[i]; else q[id[i]].k-=tmp, q2[++cnt2]=id[i]; } for(int i=l; i<=mid; ++i) add(a[i].x,a[i].y,-1); for(int i=1; i<=cnt1; ++i) id[L+i-1]=q1[i]; for(int i=1; i<=cnt2; ++i) id[L+cnt1+i-1]=q2[i]; solve(l,mid,L,L+cnt1-1); solve(mid+1,r,L+cnt1,R); } int main() { n=read(), m=read(); for(int i=1; i<=n; ++i) for(int j=1; j<=n; ++j){ a[++cnt]=Node(i,j,read()); } sort(a+1,a+cnt+1); for(int i=1; i<=m; ++i) { q[i].x1=read(), q[i].y1=read(), q[i].x2=read(), q[i].y2=read(); q[i].k=read(); id[i]=i; } solve(1,cnt,1,m); for(int i=1; i<=m; ++i) printf("%d ",ans[i]); return 0; }