【题解】P1527 [国家集训队]矩阵乘法(整体二分)

[国家集训队]矩阵乘法

题目描述

给你一个 \(n \times n\) 的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第 \(k\) 小数。

输入格式

第一行有两个整数,分别表示矩阵大小 \(n\) 和询问组数 \(q\)

\(2\) 到第 \((n + 1)\) 行,每行 \(n\) 个整数,表示这个矩阵。第 \((i + 1)\) 行的第 \(j\) 个数表示矩阵第 \(i\) 行第 \(j\) 列的数 \(a_{i, j}\)

接下来 \(q\) 行,每行五个整数 \(x_1, y_1, x_2, y_2, k\),表示一组询问,要求找到以 \((x_1, y_1)\) 为左上角,\((x_2, y_2)\) 为右下角的子矩形中的第 \(k\) 小数。

输出格式

对于每组询问,输出一行一个整数表示答案。

样例 #1

样例输入 #1

2 2
2 1
3 4
1 2 1 2 1
1 1 2 2 3

样例输出 #1

1
3

提示

数据规模与约定

  • 对于 \(20\%\) 的数据,保证 \(n \leq 100\)\(q \leq 10^3\)
  • 对于 \(40\%\) 的数据,保证 \(n \leq 300\)\(q \leq 10^4\)
  • 对于 \(60\%\) 的数据,保证 \(n \leq 400\)\(q \leq 3 \times 10^4\)
  • 对于 \(100\%\) 的数据,保证 \(1 \leq n \leq 500\)\(1 \leq q \leq 6 \times 10^4\)\(0 \leq a_{i, j} \leq 10^9\)

题解

整体二分,值域上二分
有点卡常,开O2,同时值域替换为所有数离散化后的数组上二分。

#include<bits/stdc++.h>
using namespace std;
inline int rd(){
	int f=1,j=0;
	char w=getchar();
	while(!isdigit(w)){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(isdigit(w)){
		j=j*10+w-'0';
		w=getchar();
	}
	return f*j;
}
const int N=510,M=60010,K=250010;
int n,m,cnt,ans[M],sum[N][N],tr[N][N];
struct node1{
	int lx,ly,rx,ry,k,id;
}que[M],Mid[M];
struct node2{
	int x,y,z;
}poi[K];
inline int lowbit(int x){return x&-x;}
inline void add(int x,int y,int z){
	for(int i=x;i<=n;i+=lowbit(i)){
		for(int j=y;j<=n;j+=lowbit(j)){
			tr[i][j]+=z;
		}
	}
	return ;
}
inline int get(int x,int y){
	int ansn=0;
	for(int i=x;i;i-=lowbit(i)){
		for(int j=y;j;j-=lowbit(j)){
			ansn+=tr[i][j];
		}
	}
	return ansn;
}
inline int query(int lx,int ly,int rx,int ry){
	return get(rx,ry)-get(lx-1,ry)-get(rx,ly-1)+get(lx-1,ly-1);
}
inline void modify(int l,int r,int k){
	for(int i=l;i<=r;i++)add(poi[i].x,poi[i].y,k);
	return ;
}
void deal(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[que[i].id]=poi[l].z;
		}
		return ;
	}
	int mid=(l+r)/2;
	modify(mid+1,r,-1);
//	cout<<poi[l].z<<" "<<poi[r].z<<"|"<<poi[mid].z<<"-"<<L<<" "<<R<<":"<<"\n";
	int ll=L-1,rr=R+1;
	for(int i=L;i<=R;i++){
		int k=query(que[i].lx,que[i].ly,que[i].rx,que[i].ry);
//		cout<<que[i].lx<<" "<<que[i].ly<<" "<<que[i].rx<<" "<<que[i].ry<<":"<<k<<"\n";
		if(k>=que[i].k)Mid[++ll]=que[i];
		else Mid[--rr]=que[i];
	}
	for(int i=L;i<=R;i++)que[i]=Mid[i];
	deal(l,mid,L,ll);
	modify(mid+1,r,1);
	deal(mid+1,r,rr,R);
	return ;
}
signed main(){
	n=rd(),m=rd();
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			poi[++cnt].z=sum[i][j]=rd();	
			poi[cnt].x=i,poi[cnt].y=j;
		}
	}
	for(int i=1;i<=m;i++){
		que[i].lx=rd(),que[i].ly=rd(),que[i].rx=rd(),que[i].ry=rd();
		que[i].k=rd(),que[i].id=i;
	}
	sort(poi+1,poi+1+cnt,[&](node2 a,node2 b){return a.z<b.z;});
	modify(1,cnt,1);
//	for(int i=1;i<=n;i++){
//		for(int j=1;j<=n;j++)cout<<tr[i][j]<<" ";
//		cout<<"\n";
//	}
//	cout<<"all:"<<query(1,1,n,n)<<"\n";
//	cout<<get(n,n)<<" "<<get(0,n)<<" "<<get(n,0)<<" "<<get(0,0)<<"\n";
	deal(1,cnt,1,m);
	for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
	return 0;
}
posted @ 2022-12-30 14:48  flywatre  阅读(59)  评论(0)    收藏  举报