A1333. 矩阵乘法(梁 盾)
试题来源
2012中国国家集训队命题答辩
问题描述
给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数。
输入格式
第一行两个数N,Q,表示矩阵大小和询问组数;
接下来N行N列一共N*N个数,表示这个矩阵;
再接下来Q行每行5个数描述一个询问:x1,y1,x2,y2,k表示找到以(x1,y1)为左上角、以(x2,y2)为右下角的子矩形中的第K小数。
接下来N行N列一共N*N个数,表示这个矩阵;
再接下来Q行每行5个数描述一个询问:x1,y1,x2,y2,k表示找到以(x1,y1)为左上角、以(x2,y2)为右下角的子矩形中的第K小数。
输出格式
对于每组询问输出第K小的数。
样例输入
2 2
2 1
3 4
1 2 1 2 1
1 1 2 2 3
2 1
3 4
1 2 1 2 1
1 1 2 2 3
样例输出
1
3
3
数据规模和约定
矩阵中数字是109以内的非负整数;
20%的数据:N<=100,Q<=1000;
40%的数据:N<=300,Q<=10000;
60%的数据:N<=400,Q<=30000;
100%的数据:N<=500,Q<=60000。
20%的数据:N<=100,Q<=1000;
40%的数据:N<=300,Q<=10000;
60%的数据:N<=400,Q<=30000;
100%的数据:N<=500,Q<=60000。
poj2104 k-th的二维拓展,开个二维树状数组即可!
#include<cstdio> #include<iostream> using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int N=505,Z=3.5e5+5; const int inf=2e9; struct node{ int x1,x2,y1,y2,k,opt,id; }p[Z],p1[Z],p2[Z]; int n,m,tot,BIT[N][N],ans[Z]; int mx,mn; inline int lowbit(int x){ return x&-x; } inline void update(int x,int y,int v){ for(int i=x;i<=n;i+=lowbit(i)){ for(int j=y;j<=n;j+=lowbit(j)){ BIT[i][j]+=v; } } } inline int query(int x,int y){ int res=0; for(int i=x;i;i-=lowbit(i)){ for(int j=y;j;j-=lowbit(j)){ res+=BIT[i][j]; } } return res; } void solve(int l,int r,int x,int y){ if(l>r||x>y) return ; if(x==y){ for(int i=l;i<=r;i++) if(p[i].opt) ans[p[i].id]=x; return ; } int mid=x+y>>1,i,t1(0),t2(0),tt(0); for(i=l;i<=r;i++){ if(!p[i].opt){ if(p[i].k<=mid){ p1[++t1]=p[i]; update(p1[t1].x1,p1[t1].y1,1); } else{ p2[++t2]=p[i]; } } else{ tt=query(p[i].x2,p[i].y2)-query(p[i].x1-1,p[i].y2)-query(p[i].x2,p[i].y1-1)+query(p[i].x1-1,p[i].y1-1); if(p[i].k<=tt){ p1[++t1]=p[i]; } else{ p[i].k-=tt; p2[++t2]=p[i]; } } } for(i=1;i<=t1;i++) if(!p1[i].opt) update(p1[i].x1,p1[i].y1,-1); for(i=1;i<=t1;i++) p[l+i-1]=p1[i]; for(i=1;i<=t2;i++) p[l+t1+i-1]=p2[i]; solve(l,l+t1-1,x,mid); solve(l+t1,r,mid+1,y); } int main(){ mx=-inf;mn=inf; n=read();m=read(); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ p[++tot].opt=0; p[tot].x1=i; p[tot].y1=j; p[tot].k=read(); mx=max(mx,p[tot].k); mn=min(mn,p[tot].k); } } for(int i=1;i<=m;i++){ p[++tot].opt=1; p[tot].x1=read(); p[tot].y1=read(); p[tot].x2=read(); p[tot].y2=read(); p[tot].k=read(); p[tot].id=i; } solve(1,tot,mn,mx); for(int i=1;i<=m;i++) printf("%d ",ans[i]); return 0; }