logo AlgoBeat OnlineJudge
登录 注册

题解

作者: _ZXY_  ·  发布于 2026-06-12 16:29:23  ·  最后修改于 2026-06-12 17:32:15
已通过
审核员:Lemon_zqp 弱弱 · 2026-06-12 17:32:15

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

考虑 的数据。
不难想到暴力二分,遍历矩阵,计算 的数的个数。
为值域上界,总体时间复杂度为

考虑 的数据。
发现与普通区间 kth 的区别在于这题的 是二维的。
同样,我们可以将 存成一维数组形式,利用二维树状数组来整体二分。
表示询问 的答案在 中(此处 指一维数组)。函数内部,我们将 的数染黑,利用二维树状数组结合 计算询问区间内黑点个数,递归处理左右区间。
由于二维树状数组单次修改查询是 的,所以时间复杂度为

#include<bits/stdc++.h>
using namespace std;
const int N=507,M=6e4+7;
int tr[N][N],id[M],n;
int lowbit(int x){
	return x&-x;
}
void add(int x,int y,int c){
	for(int i=x;i<=n;i+=lowbit(i)){
		for(int j=y;j<=n;j+=lowbit(j)){
			tr[i][j]+=c;
		}
	}
}
int query(int x,int y){
	int res=0;
	for(int i=x;i>0;i-=lowbit(i)){
		for(int j=y;j>0;j-=lowbit(j)){
			res+=tr[i][j];
		}
	}
	return res;
}
struct node{
	int x,y,v;
	bool operator<(node a)const{
		return v<a.v;
	}
}mat[N*N];
struct Q{
	int x_1,y_1,x_2,y_2,k; 
}q[M];
int cas,cur[M],q1[M],q2[M],ans[M];
int get(int x,int y){
	return (x-1)*n+y;
}
void Solve(int l,int r,int ql,int qr){
	if(ql>qr)return;
	if(l==r){
		for(int i=ql;i<=qr;i++)ans[id[i]]=mat[l].v;
		return;
	}
	int mid=(l+r)>>1;
	int cnt1=0,cnt2=0;
	for(int i=l;i<=mid;i++)add(mat[i].x,mat[i].y,1);
	for(int i=ql;i<=qr;i++){
		int sum=query(q[id[i]].x_2,q[id[i]].y_2)-query(q[id[i]].x_1-1,q[id[i]].y_2)-
			query(q[id[i]].x_2,q[id[i]].y_1-1)+query(q[id[i]].x_1-1,q[id[i]].y_1-1); 
		int num=cur[id[i]]+sum;
		if(num>=q[id[i]].k)q1[++cnt1]=id[i];
		else q2[++cnt2]=id[i],cur[id[i]]=num;
	}
	for(int i=l;i<=mid;i++)add(mat[i].x,mat[i].y,-1);
	int qcnt=ql;
	for(int i=1;i<=cnt1;i++)id[qcnt++]=q1[i];
	for(int i=1;i<=cnt2;i++)id[qcnt++]=q2[i];
	Solve(l,mid,ql,ql+cnt1-1);
	Solve(mid+1,r,ql+cnt1,qr);
}
void solve(){
	//start
	cin.tie(0)->ios::sync_with_stdio(0);
	cout.tie(0);
	cin>>n>>cas;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			int x;
			cin>>x;
			mat[get(i,j)]={i,j,x};
		}
	}
	sort(mat+1,mat+n*n+1);
	for(int i=1;i<=cas;i++){
		cin>>q[i].x_1>>q[i].y_1>>q[i].x_2>>q[i].y_2>>q[i].k;
		id[i]=i;
	}
	Solve(1,n*n,1,cas);
	for(int i=1;i<=cas;i++)cout<<ans[i]<<endl;
}
int main(){
	solve();
	return 0;
}

暂无评论

登录 后即可评论。