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

[国家集训队]矩阵乘法

题目描述

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

输入格式

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

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

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

输出格式

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

样例 #1

样例输入 #1

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

样例输出 #1

1
3

提示

数据规模与约定

  • 对于 20% 的数据,保证 n100q103
  • 对于 40% 的数据,保证 n300q104
  • 对于 60% 的数据,保证 n400q3×104
  • 对于 100% 的数据,保证 1n5001q6×1040ai,j109

题解

整体二分,值域上二分
有点卡常,开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 @   flywatre  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示