ZOJ 1859 Matrix Searching(二维线段树)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1859

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


Author: PENG, Peng

Source: ZOJ Monthly, June 2007

题意:

给出一个n*n的矩阵,有m次询问,求每次询问子矩阵中的最小值。

分析:

显然二维线段树随便乱搞搞即可了,线段树维护区域内的最小值。注意二维上的"pushup()"的写法,实际上也是要维护一棵线段树。

/*
 *
 *	Author	:	fcbruce
 *
 *	Date	:	2014-08-24 13:03:05
 *
 */
#include <cstdio>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <cctype>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <map>
#include <set>
#define sqr(x) ((x)*(x))
#define LL long long
#define itn int
#define INF 0x3f3f3f3f
#define PI 3.1415926535897932384626
#define eps 1e-10

#ifdef _WIN32
	#define lld "%I64d"
#else
	#define lld "%lld"
#endif

#define maxm
#define maxn 300

using namespace std;

int n;
int minv[maxn<<2][maxn<<2];

inline void pushup(int k_2d,int k)
{
	minv[k_2d][k]=min(minv[k_2d][k*2+1],minv[k_2d][k*2+2]);
}

void build_1d(int k,int l,int r,int k_2d,int type)
{
	if (r-l==1)
	{
		if (type)
			scanf( "%d",&minv[k_2d][k]);
		else
			minv[k_2d][k]=min(minv[k_2d*2+1][k],minv[k_2d*2+2][k]);

		return ;
	}

	build_1d(k*2+1,l,l+r>>1,k_2d,type);
	build_1d(k*2+2,l+r>>1,r,k_2d,type);

	pushup(k_2d,k);
}

void build_2d(int k,int l,int r)
{
	if (r-l==1)
		build_1d(0,0,n,k,1);
	else
	{
		build_2d(k*2+1,l,l+r>>1);
		build_2d(k*2+2,l+r>>1,r);

		build_1d(0,0,n,k,0);
	}
}

int query_1d(int a,int b,int k,int l,int r,int k_2d)
{
	if (b<=l || r<=a)	return INF;
	if (a<=l && r<=b)	return minv[k_2d][k];

	return min(query_1d(a,b,k*2+1,l,l+r>>1,k_2d),query_1d(a,b,k*2+2,l+r>>1,r,k_2d));

}

int query_2d(int a,int b,int ya,int yb,int k,int l,int r)
{
	if (b<=l || r<=a)	return INF;
	if (a<=l && r<=b)	return query_1d(ya,yb,0,0,n,k);

	return min(query_2d(a,b,ya,yb,k*2+1,l,l+r>>1),query_2d(a,b,ya,yb,k*2+2,l+r>>1,r));
}

int main()
{
	#ifndef ONLINE_JUDGE
		freopen("/home/fcbruce/文档/code/t","r",stdin);
	#endif // ONLINE_JUDGE

	int T_T;
	scanf( "%d",&T_T);

	while (T_T--)
	{
		scanf( "%d",&n);
		build_2d(0,0,n);

		int m;
		scanf( "%d",&m);
		int x1,x2,y1,y2;
		while (m--)
		{
			scanf( "%d%d%d%d",&x1,&y1,&x2,&y2);
			x1--;
			y1--;
			printf( "%d\n",query_2d(x1,x2,y1,y2,0,0,n));
		}
	}

	return 0;
}
时间: 2024-08-03 07:11:55

ZOJ 1859 Matrix Searching(二维线段树)的相关文章

zoj 2589 Matrix Searching 二维线段树

题目链接 给一个n*n的矩阵, 给q个查询, 每次给出x1, y1, x2, y2, 求这个矩阵中的最小值. 代码基本上和上一题相同... 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define pb(x) push_back(x) 4 #define ll long long 5 #define mk(x, y) make_pair(x, y) 6 #define lson l, m, rt<<1 7 #define

[POJ2155] Matrix(二维线段树,树套树)

题目链接:http://poj.org/problem?id=2155 题意:给一个01矩阵,两个操作,翻转:子矩阵里每一个数都由0变1,1变0. 查询:查询某一点是0还是1. 一直以为二维线段树就是开一个线段树数组的我- 这题暴力更新每一个小矩形,翻转就+1,最后看看某点的奇偶. 写屎了,特别注意的是在外层查询的时候要先把当前层的内层query掉,接着再向下扩展.这样外层就不用lazy啦 1 #include <algorithm> 2 #include <iostream> 3

POJ 2155 Matrix【二维线段树】

题目大意:给你一个全是0的N*N矩阵,每次有两种操作:1将矩阵中一个子矩阵置反,2.查询某个点是0还是1 思路:裸的二维线段树 #include<iostream>#include<cstdio>#include <math.h>#include<algorithm>#include<string.h>#include<queue>#define MOD 1000003#define maxn 4009#define LL long

ZOJ 2859 二维线段树

思路:自己写的第二发二维线段树1A,哈哈,看来对二维的push操作比较了解了:但是还没遇到在两个线段树中同时进行push操作的,其实这题我是想在x维和y维同时进行push操作的,但是想了好久不会,然后看到这题又给出10秒,然后想想在x维线段直接单点查询肯定也过了,然后在第二维就只有pushup操作,在第一维线段树没有pushup操作.要是在第一维也有pushup操作的话,那就不用单点查询那么慢了.不过也A了,想找题即在二维同时进行pushup和pushdown操作的. #include<iost

POJ 2155 Matrix (二维线段树)

http://poj.org/problem?id=2155 Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 18143   Accepted: 6813 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. I

POJ2155 Matrix二维线段树经典题

题目链接 二维树状数组 1 #include<iostream> 2 #include<math.h> 3 #include<algorithm> 4 #include<stdlib.h> 5 using namespace std; 6 #define ll long long 7 #define re(i,n) for(int i=0;i<n;i++) 8 const int maxn = 1007; 9 int c[maxn][maxn]; 10

POJ 2155 Matrix 二维线段树+标记永久化?

题意:链接 方法:二维线段树+标记永久化 解析:题意是比较明朗的,算一下内存发现4000^2也是可以接受的,于是就开始yy二维线段树? 对于第一层x的线段树,每个节点开一整棵y线段树. 用个二维数组就实现了? 不过发现个问题啊,这题怎么pushdown啊,标记传不下去啊.如果给x打个标记那么怎么知道y传那段啊? 于是就学了新的东西?标记永久化. 本题是单点查询嘛,标记永久化就应该是把相应的区间直接异或,不用往下传?那查询的时候怎么办呢?只需要在查询的时候把所有路过该点的区间都异或起来就OK了.貌

poj2155 Matrix 二维线段树

二维线段树区间更新和单点查询,由于二维线段树不能传递标记,所以区间更新和一维不太一样,需要用到被更新的值以及更新操作的一些性质,还有要注意对query的影响. 这里操作是翻转,而且是单点查询,所以就直接在矩形块内更新,不把标记传递下去,查询的时候做一下微调,把所有经过的路径的标记都判断一遍,看是否需要翻转,这样就解决了这道题. 上一道是单点更新和区间求和,当然就不用标记了,把所有的第一维的第二层的y点全部更新,查询的时候不用查到最底层也能查到了. 二维线段树还是比较灵活,但这已经是最简单的树套树

POJ1195 Mobile phones 【二维线段树】

Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14291   Accepted: 6644 Description Suppose that the fourth generation mobile phone base stations in the Tampere area operate as follows. The area is divided into squares. The