首页 > 代码库 > BZOJ 2738 矩阵乘法 整体二分+二维树状数组

BZOJ 2738 矩阵乘法 整体二分+二维树状数组

题目大意:给定一个矩阵,多次求某个子矩阵中的第k小

分块解法见 http://blog.csdn.net/popoqqq/article/details/41356899

《论除最小割外题目解法从来与题目名称无关系列》

整体二分 Solve(x,y,S)表示处理答案在[x,y]区间内的询问集合S

预先将所有数按照大小排序 每次将[1,mid]之间的数插入树状数组

然后对于分治内部的每一个询问 去树状数组中查询相应子矩阵的数值

如果小于等于k就划分到左集合S1 否则划分到右集合S2

然后Solve(x,mid,S1),Solve(mid+1,y,S2)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 550
using namespace std;
struct abcd{
	int val,x,y;
	bool operator < (const abcd &a) const
	{
		return val < a.val;
	}
}a[M*M];
struct query{
	int x1,y1,x2,y2,k;
	void Read()
	{
		scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&k);
	}
}mempool[60600],*q[60600],*nq[60600];
int n,m,max_num,now;
int ans[60600];
namespace BIT{
	int c[M][M];
	inline void Update(int x,int y,int flag)
	{
		int i,j;
		for(i=x;i<=n;i+=i&-i)
			for(j=y;j<=n;j+=j&-j)
				c[i][j]+=flag;
	}
	inline int Get_Ans(int x,int y)
	{
		int i,j,re=0;
		for(i=x;i;i-=i&-i)
			for(j=y;j;j-=j&-j)
				re+=c[i][j];
		return re;
	}
}
void Holistic_Bisection(int x,int y,int l,int r)
{
	using namespace BIT;
	int i,mid=x+y>>1;
	if(l>r) return ;
	if(x==y)
	{
		for(i=l;i<=r;i++)
			ans[q[i]-mempool]=mid;
		return ;
	}
	while( now!=n*n && a[now+1].val<=mid )
	{
		++now;
		Update(a[now].x,a[now].y,1);
	}
	while( now && a[now].val>mid )
	{
		Update(a[now].x,a[now].y,-1);
		--now;
	}
	int _l=l,_r=r;
	for(i=l;i<=r;i++)
	{
		int temp=Get_Ans(q[i]->x2,q[i]->y2)-Get_Ans(q[i]->x1-1,q[i]->y2)
				-Get_Ans(q[i]->x2,q[i]->y1-1)+Get_Ans(q[i]->x1-1,q[i]->y1-1);
		if(q[i]->k<=temp)
			nq[_l++]=q[i];
		else
			nq[_r--]=q[i];
	}
	memcpy(q+l,nq+l,sizeof(q[0])*(r-l+1) );
	Holistic_Bisection(x,mid,l,_l-1);
	Holistic_Bisection(mid+1,y,_r+1,r);
}
int main()
{
	int i,j;
	cin>>n>>m;
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++)
		{
			scanf("%d",&a[i*n-n+j].val);
			a[i*n-n+j].x=i;
			a[i*n-n+j].y=j;
			max_num=max(max_num,a[i*n-n+j].val);
		}
	sort(a+1,a+n*n+1);
	for(i=1;i<=m;i++)
	{
		mempool[i].Read();
		q[i]=&mempool[i];
	}
	Holistic_Bisection(0,max_num,1,m);
	for(i=1;i<=m;i++)
		printf("%d\n",ans[i]);
	return 0;
}


BZOJ 2738 矩阵乘法 整体二分+二维树状数组