bzoj2738矩陣乘法

Description

  給你一個N*N的矩陣,不用算矩陣乘法,但是每次詢問一個子矩形的第K小數。

Input

 
  第一行兩個數N,Q,表示矩陣大小和詢問組數;
  接下來N行N列一共N*N個數,表示這個矩陣;
  再接下來Q行每行5個數描述一個詢問:x1,y1,x2,y2,k表示找到以(x1,y1)爲左上角、以(x2,y2)爲右下角的子矩形中的第K小數。

Output

  對於每組詢問輸出第K小的數。

Sample Input

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

Sample Output

1
3

HINT

  矩陣中數字是109以內的非負整數;

  20%的數據:N<=100,Q<=1000;

  40%的數據:N<=300,Q<=10000;

  60%的數據:N<=400,Q<=30000;

  100%的數據:N<=500,Q<=60000。


據說正解是整體二分,然而看了半天並沒有看懂,最後選擇了分塊
首先將矩陣裏的數字排序,然後每次插size個,插入後暴力掃一遍詢問,如果有詢問的區間在本次操作中數字個數大於了k,就說明查詢的k值在剛剛插入的
size個數中,此時再暴力倒序掃一遍剛剛的size個數字就好了,二位前綴和維護矩陣內數字的個數,鏈表維護詢問即可
代碼
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#define maxn 505
#define maxq 60005
using namespace std;
inline void read(int& x)
{	char c=getchar();x=0;int y=1;
	while(c<'0'||c>'9'){if(c=='-') y=-1;c=getchar();}
	while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
	x*=y;
}
template<typename T>inline T m_min(T x,T y){return x<y?x:y;}
int n,q,sum[maxn][maxn],sz,ans[maxq],done,cnt,pre[maxq],nex[maxq],A[maxn][maxn];
struct query
{	int x1,x2,y1,y2,k;
	query(int a=0,int b=0,int c=0,int d=0,int e=0):x1(a),x2(b),y1(c),y2(d),k(e){}
}Q[maxq];
struct node
{	int x,y,v;
	node(int x=0,int y=0,int z=0):x(x),y(y),v(z){}
	friend bool operator<(const node& a,const node& b){return a.v<b.v;}
}matrix[maxn*maxn];
int main()
{	read(n);read(q);int x,y,a,b,c;
	for(int i=1;i<=n;++i)	
		for(int j=1;j<=n;++j)
		{	read(x);
			matrix[++cnt]=node(i,j,x);
		}
	for(int i=1;i<=q;++i)
	{	read(x);read(y);read(a),read(b);read(c);
		Q[i]=query(x,a,y,b,c);
		pre[i]=i-1;nex[i]=i+1;
	}
	nex[0]=1;
	sort(matrix+1,matrix+cnt+1);
	register int i,j,k,lef,rig,_,__;
	int now;
	for(i=1;i<=n;++i)
	{	lef=(i-1)*n+1;rig=lef+n-1;
		for(j=lef;j<=rig;++j)
			A[matrix[j].x][matrix[j].y]=1;
		for(_=1;_<=n;++_)
			for(__=1;__<=n;++__)
				sum[_][__]=sum[_][__-1]+sum[_-1][__]-sum[_-1][__-1]+A[_][__];
		for(j=nex[0];j<=q;j=nex[j])
		{	now=sum[Q[j].x2][Q[j].y2]-sum[Q[j].x2][Q[j].y1-1]-sum[Q[j].x1-1][Q[j].y2]+sum[Q[j].x1-1][Q[j].y1-1];
			if(now>=Q[j].k)
				for(int l=rig;l>=lef;--l)
					if(matrix[l].x>=Q[j].x1&&matrix[l].x<=Q[j].x2&&matrix[l].y>=Q[j].y1&&matrix[l].y<=Q[j].y2)
					{   --now;
						if(now<Q[j].k)
						{	ans[j]=matrix[l].v;++done;
							nex[pre[j]]=nex[j];pre[nex[j]]=pre[j];
							break;
						}
					}
		}
		if(done==q) break;
	}
	for(int i=1;i<=q;++i) printf("%d\n",ans[i]);
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章