二维线段树 UVa 11992 - Fast Matrix Operations

给一个总元素个数为n(n≤1000000) 的矩阵,矩阵长度为 (r≤20),宽度为 c,矩阵初始值全为整数 0。定义一个子矩阵 (x1,y1),(x2,y2)(包括边界),操作有三种:

将子矩阵的每个元素加上一个值v(v>0)。
将子矩阵的每个元素赋值为v(v≥0)。
查询子矩阵所有元素的和,最小值,最大值。
样例输入
4 4 8
1 1 2 4 4 5
3 2 1 4 4
1 1 1 3 4 2
3 1 2 4 4
3 1 1 3 4
2 2 1 4 4 2
3 1 2 4 4
1 1 1 4 3 3
样例输出
45 0 5
78 5 7
69 2 7
39 2 7
附加输入
1 2 8
1 1 1 1 2 1
3 1 1 1 2
1 1 1 1 1 1
3 1 1 1 2
2 1 2 1 2 3
3 1 1 1 2
1 1 1 1 2 3
3 1 1 1 2
附加输出
2 1 1
3 1 2
5 2 3
11 5 6

 

https://blog.sengxian.com/solutions/uva-11992

 

#include <cstdio>
#include <cstring>
 
#define clear( A , X ) memset ( A , X , sizeof A )
#define lson l , m , o << 1
#define rson m + 1 , r , o << 1 | 1
 
const int maxR = 22 ;
const int maxC = 200005 ;
const int oo = 0x3f3f3f3f ;
 
int max[maxR][maxC] , min[maxR][maxC] , sum[maxR][maxC] ;
int add[maxR][maxC] , set[maxR][maxC] ;
 
int Min ( const int X , const int Y ) 
{
	if ( X < Y ) return X ;
	return Y ;
}
 
int Max ( const int X , const int Y ) 
{
	if ( X > Y ) return X ; 
	return Y ;
}
 
void PushUp ( int x , int o ) 
{
	sum[x][o] = sum[x][o << 1] + sum[x][o << 1 | 1] ;
	min[x][o] = Min ( min[x][o << 1] , min[x][o << 1 | 1] ) ;
	max[x][o] = Max ( max[x][o << 1] , max[x][o << 1 | 1] ) ;
}
 
void PushDown ( int x , int l , int r , int o ) 
{
	int m = ( l + r ) >> 1 ;
	if ( set[x][o] ) //如果存在强制归为某个数的操作 
	{
		int tmp = set[x][o] ;
		set[x][o << 1] = tmp ;//下放到子结点 
		min[x][o << 1] = tmp ;//最小值,最大值都发生变化 
		max[x][o << 1] = tmp ;
		sum[x][o << 1] = tmp * ( m - l + 1 ) ;
		//区间总和也要发生变化  
		add[x][o << 1] =   0 ;
		//从前打过的加法的标记归0 
		
		set[x][o << 1 | 1] = tmp ;
		min[x][o << 1 | 1] = tmp ;
		max[x][o << 1 | 1] = tmp ;
		sum[x][o << 1 | 1] = tmp * ( r - m ) ;
		add[x][o << 1 | 1] =   0 ;
		
		set[x][o] = 0 ;
	}
	if ( add[x][o] ) 
	{
		int tmp = add[x][o] ;
		add[x][o << 1] += tmp ;
		min[x][o << 1] += tmp ;
		max[x][o << 1] += tmp ;
		sum[x][o << 1] += tmp * ( m - l + 1 ) ;
		
		add[x][o << 1 | 1] += tmp ;
		min[x][o << 1 | 1] += tmp ;
		max[x][o << 1 | 1] += tmp ;
		sum[x][o << 1 | 1] += tmp * ( r - m ) ;
		
		add[x][o] = 0 ;
	}
}
 
void Build ( int x , int l , int r , int o ) 
//x代表这是第多少个线段树,它的o这个结点管辖[L,R]这一段 
{
	set[x][o] = add[x][o] = 0 ;
	if ( l == r ) 
	{
		min[x][o] = max[x][o] = sum[x][o] = 0 ;
		return ;
	}
	int m = ( l + r ) >> 1 ;
	Build ( x , lson ) ;
	Build ( x , rson ) ;
}
 
void Set ( int L , int R , int v , int x , int l , int r , int o ) 
{
	if ( L <= l && r <= R ) 
	{
		add[x][o] = 0 ;
		set[x][o] = v ;
		min[x][o] = v ;
		max[x][o] = v ;
		sum[x][o] = v * ( r - l + 1 ) ;
		return ;
	}
	PushDown ( x , l , r , o ) ;
	int m = ( l + r ) >> 1 ;
	if ( L <= m ) 
	     Set ( L , R , v , x , lson ) ;
	if ( m <  R ) 
	    Set ( L , R , v , x , rson ) ;
	PushUp ( x , o ) ;
}
 
void Add ( int L , int R , int v , int x , int l , int r , int o ) {
	if ( L <= l && r <= R ) {
		add[x][o] += v ;
		min[x][o] += v ;
		max[x][o] += v ;
		sum[x][o] += v * ( r - l + 1 ) ;
		return ;
	}
	PushDown ( x , l , r , o ) ;
	int m = ( l + r ) >> 1 ;
	if ( L <= m ) Add ( L , R , v , x , lson ) ;
	if ( m <  R ) Add ( L , R , v , x , rson ) ;
	PushUp ( x , o ) ;
}
 
int ansmin , ansmax , anssum ;
 
void Query ( int L , int R , int x , int l , int r , int o ) {
	if ( L <= l && r <= R ) {
		ansmin = Min ( ansmin , min[x][o] ) ;
		ansmax = Max ( ansmax , max[x][o] ) ;
		anssum += sum[x][o] ;
		return ;
	}
	PushDown ( x , l , r , o ) ;
	int m = ( l + r ) >> 1 ;
	if ( L <= m ) Query ( L , R , x , lson ) ;
	if ( m <  R ) Query ( L , R , x , rson ) ;
}
 
void work () {
	int n , m , q , ch , x1 , x2 , y1 , y2 , v ;
	while ( ~scanf ( "%d%d%d" , &n , &m , &q ) ) 
	{
		for ( int i = 1 ; i <= n ; ++ i ) 
		     Build ( i , 1 , m , 1 ) ;
		while ( q -- ) 
		{
			scanf ( "%d" , &ch ) ;
			if ( 1 == ch ) {
				scanf ( "%d%d%d%d%d" , &x1 , &y1 , &x2 , &y2 , &v ) ;
				for ( int i = x1 ; i <= x2 ; ++ i ) 
				{
					Add ( y1 , y2 , v , i , 1 , m , 1 ) ;
					//在第i个线段树上[y1,y2]这一段上加上数字v 
				}
			}
			if ( 2 == ch ) 
			{
				scanf ( "%d%d%d%d%d" , &x1 , &y1 , &x2 , &y2 , &v ) ;
				for ( int i = x1 ; i <= x2 ; ++ i ) {
					Set ( y1 , y2 , v , i , 1 , m , 1 ) ;
				}
			}
			if ( 3 == ch ) 
			{
				scanf ( "%d%d%d%d" , &x1 , &y1 , &x2 , &y2 ) ;
				ansmin =  oo ;
				ansmax =   0 ;
				anssum =   0 ;
				for ( int i = x1 ; i <= x2 ; ++ i ) 
				{
					Query ( y1 , y2 , i , 1 , m , 1 ) ;
				}
				printf ( "%d %d %d\n" , anssum , ansmin , ansmax ) ;
			}
		}
	}
}
 
int main () {
	work () ;
	return 0 ;
}
————————————————
版权声明:本文为CSDN博主「poursoul」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u013368721/article/details/32695823

  

posted @ 2021-04-03 00:05  我微笑不代表我快乐  阅读(3)  评论(0编辑  收藏  举报