您的位置:首页 > 编程语言 > PHP开发

Zju -- 2859 Matrix Searching(线段树)

2011-04-23 13:40 295 查看
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2859

 

Matrix Searching
Time Limit: 10 Seconds Memory Limit: 32768 KB

Given an n*n matrix A, whose entries Ai,j are integer numbers ( 1 <= i <= n, 1 <= j <= n ). An operation FIND the minimun number in a given ssub-matrix.

Input

The first line of the input contains a single integer T , the number of test cases.

For each test case, the first line contains one integer n (1 <= n <= 300), which is the sizes of the matrix, respectively. The next n lines with n integers each gives the elements of the matrix.

The next line contains a single integer N (1 <= N <= 1,000,000), the number of queries. The next N lines give one query on each line, with four integers r1, c1, r2, c2 (1 <= r1 <= r2 <= n, 1 <= c1 <= c2 <= n), which are the indices of the upper-left corner and lower-right corner of the sub-matrix in question.

Output

For each test case, print N lines with one number on each line, the required minimum integer in the sub-matrix.

Sample Input

1
2
2 -1
2 3
2
1 1 2 2
1 1 2 1

Sample Output

-1
2

 

题意:
  给定一个n*n(n <= 300)的矩阵,

给出 a,b,c,d 

询问a行b列到c行d列矩阵中的最小值。

 

思路:
一维线段树是一颗完全二叉树,那么二维线段树无疑就是一颗完全四叉树,换言
之,每个结点有四个儿子,这里为了空间不浪费,将所有结点记录在一个一维数组中
,每个结点的四个儿子采用编号的方式存储,在建树之前将每个结点的信息全部初始
化,初始化的时候需要注意的是每次将当前结点的四个儿子清空,然后判断它本身是
否是叶子结点,可以通过x和y区间端点是否重合来判断,最后再来生成四个儿子编号
,然后往下递归,递归结束后根据四个儿子的最小值更新当前的最小值。再来看询问
,和一维的情况类似,一维是对区间交,而二维则是对矩形交,如果询问的二维区间
和当前结点管理的二维区间没有交集,显然不可能有最小值,直接返回inf,否则如果
询问的二维区间完全包含了当前结点管理的二维区间,那么返回结点最小值。否则递
归当前结点的四个儿子,取最小值,回归到根节点就得到了询问区间的最值了。
需要注意的是在建树的时候不要在叶子结点生成多余的儿子结点,这样内存会多
一倍,如果开得不够大有可能下标越界,开得太大有可能超内存。还有就是在二维线
段树的结点上信息会多了不少,能节省空间尽量节省,比如每个结点管理的区间端点
不可能很大,所以不需要int,short就足够了。

 

#include <iostream>
#include <cmath>
#include <cstdio>
#define  min(a,b) a<b?a:b
#define inf 2100000000
#define Maxn 310
using namespace std;

struct node
{
int min,child[4];
short x0,x1,y0,y1;
}Tree[Maxn*Maxn*4];
int num[310][310],n;
int index;
void build(int k,int x0,int x1,int y0,int y1)
{
Tree[k].x0=x0;
Tree[k].x1=x1;
Tree[k].y0=y0;
Tree[k].y1=y1;
Tree[k].min=inf;
if(x0==x1&&y0==y1)
Tree[k].min=num[x0][y0];
else
{
int midx=(x0+x1)>>1;
int midy=(y0+y1)>>1;
Tree[k].child[0]=++index;
build(index,x0,midx,y0,midy);
Tree[k].child[1]=++index;
build(index,midx<x1?midx+1:x1,x1,y0,midy);
Tree[k].child[2]=++index;
build(index,x0,midx,midy+1<y1?midy+1:y1,y1);
Tree[k].child[3]=++index;
build(index,midx+1<x1?midx+1:x1,x1,midy+1<y1?midy+1:y1,y1);
Tree[k].min=Tree[Tree[k].child[0]].min;
for(int i=1;i<4;i++)
if(Tree[Tree[k].child[i]].min<Tree[k].min)
Tree[k].min=Tree[Tree[k].child[i]].min;
}

}
int quary(int k, int x0, int x1, int y0, int y1)
{
if(x0>Tree[k].x1||x1<Tree[k].x0
|| y0>Tree[k].y1||y1<Tree[k].y0)
return inf;

if(x0<=Tree[k].x0 && Tree[k].x1<=x1
&& y0<=Tree[k].y0 && Tree[k].y1<= y1)
return Tree[k].min;
int i;
int Min = inf;
for(i = 0; i < 4; i++)
{
int t = quary(Tree[k].child[i], x0, x1, y0, y1);
if(t < Min)
Min = t;
}
return Min;
}
int main()
{
int t,j,i,q,x0,x1,y0,y1;
scanf("%d",&t);
while (t--)
{
scanf("%d",&n);
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
scanf("%d",&num[i][j]);
index=0;
build(0,1,n,1,n);		//x=行,y=列
scanf("%d",&q);
while(q--)
{
scanf("%d%d%d%d",&x0,&y0,&x1,&y1);
printf("%d/n",quary(0,x0,x1,y0,y1));
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息