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就足够了。
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)); } } }
相关文章推荐
- ZOJ 2859 二维线段树
- 【BZOJ 1901】Zju2112 Dynamic Rankings &&【COGS 257】动态排名系统 树状数组套线段树
- zoj 2859(二维线段树)
- BZOJ 1901(Zju2112 Dynamic Rankings-区间第k大(修改,在线)-函数式线段树)
- [bzoj1901][Zju2112]Dynamic Rankings【树套树】【树状数组】【线段树】
- ZJU 3686 线段树
- zoj zju 3597 Hit the Target! 线段树 扫描线
- ZOJ-2859 Matrix Searching (二维线段树)
- Bzoj 1901: Zju2112 Dynamic Rankings 树套树,线段树,平衡树,Treap
- [bzoj]-1901-Zju2112 Dynamic Rankings-可持久化线段树
- ZJU 3349 线段树优化DP
- ZOJ 2859 Matrix Searching 二维线段树 || 二维RMQ
- [Zju 2112][逆序对统计] 线段树(四) {线段树扩展}
- BZOJ[1901]Zju2112 Dynamic Rankings 树套树(线段树套Splay)
- ZOJ 2859 二维线段树
- zoj 2859 二维线段树 插点求线
- 【树状数组套权值线段树】bzoj1901 Zju2112 Dynamic Rankings
- zoj zju 3324 线段树 离散化
- [树状数组套权值线段树] BZOJ 1901 Zju2112 Dynamic Rankings
- ZOJ 2859 Matrix Searching(二维线段树)