博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

zoj 2859 RMQ问题 使用分割法求解

Posted on 2011-03-09 14:19  天地玄黄  阅读(305)  评论(0编辑  收藏  举报

把整个矩阵按sqrt(n)为一块,分成n/sqrt(n)块,在查询的时候就按照小块进行分割。边缘部分按照顺时针分成相同的小条。

边

代码如下:

/*The solution of RMQ using a <O(n), O(sqrt(n))> algrithom
 *http://www.topcoder.com/tc?module=Static&d1=tutorials&d2=lowestCommonAncestor
 */
#include <stdio.h>

#define min(a,b) (((a)<(b))?(a):(b))
#define N 310

int matrix[N][N];
int M[17][17];

int mysqrt(int n)
{
	int pos = 0, i = 0;
	while(i <= n)
	{
		if( (pos+1)*(pos+1) == i)
			pos += 1;
		i++;
	}
	return pos;
}

int minMatrix(int choose, int i, int j, int u, int v)
{
	int k, t;
	int min;
	int flag = 0;

	switch(choose)
	{
	case 1:
		min = matrix[i][j];
		for(k = i; k <= u; k++)
			for(t = j; t <= v; t++)
			{
				flag = 1;
				if(matrix[k][t] < min)
					min = matrix[k][t];
			}
		break;

	case 2:
		min = M[i][j];
		for(k = i; k <= u; k++)
			for(t = j; t <= v; t++)
			{
				flag = 1;
				if(M[k][t] < min)
					min = M[k][t];
			}
		break;
	}

	return flag?min:0x7FFFFFFF;
}

void initCUT(int n)
{
	int sn = mysqrt(n);
	int block = n/sn;
	int i, j;
	for(i = 0; i < block; i++)
		for(j = 0; j < block; j++)
		{
			M[i][j] = minMatrix(1, sn*i, sn*j, sn*(i+1)-1, sn*(j+1)-1);
		}
}

int askCUT(int n, int r1, int c1, int r2, int c2)
{
	int sn = mysqrt(n);

	if(r2-r1+1<2*sn || c2-c1+1<2*sn)
	{
		return minMatrix(1, r1, c1, r2, c2);
	}

	/*subtitle in M[][]*/
	int a = (r1%sn == 0)?(r1/sn):(r1/sn+1),
		b = (c1%sn == 0)?(c1/sn):(c1/sn+1),
		c = ((r2+1)%sn == 0)?(r2/sn):(r2/sn-1),
		d = ((c2+1)%sn == 0)?(c2/sn):(c2/sn-1);

	/*subtitle in matrix[][]*/
	int lt = a*sn,/*left top*/
		rt = b*sn,/*right top*/
		ld = (c+1)*sn - 1,/*left down*/
		rd = (d+1)*sn - 1;/*rignt down*/

	int min1 = minMatrix(2, a, b, c, d);

	int min2 = minMatrix(1, r1, c1, lt-1, rd);
	int min3 = minMatrix(1, r1, rd+1, ld, c2);
	int min4 = minMatrix(1, ld+1, rt, r2, c2);
	int min5 = minMatrix(1, lt, c1, r2, rt-1);

	int min6 = min(min(min2, min3), min(min4, min5));

	return min(min1, min6);
}

int main()
{
	int t;
	scanf("%d", &t);
	while(t--)
	{
		int n;
		scanf("%d", &n);
		
		int i, j;
		for(i = 0; i < n; i++)
			for(j = 0; j < n; j++)
				scanf("%d", &(matrix[i][j]));

		if(n > 3)
			initCUT(n);

		int queries;
		scanf("%d", &queries);
		
		while(queries--)
		{
			int r1, c1, r2, c2;
			scanf("%d%d%d%d", &r1, &c1, &r2, &c2);
			if(n > 3)
				printf("%d\n", askCUT(n, r1-1, c1-1, r2-1, c2-1));
			else
				printf("%d\n", minMatrix(1, r1-1, c1-1, r2-1, c2-1));
		}
	}

	return 0;
}

参考算法:http://www.topcoder.com/tc?module=Static&d1=tutorials&d2=lowestCommonAncestor