首页 > 代码库 > UVA11992 - Fast Matrix Operations ( 线段树 + 区间修改 + 好题 )

UVA11992 - Fast Matrix Operations ( 线段树 + 区间修改 + 好题 )

 

 

UVA11992 - Fast Matrix Operations ( 线段树 + 区间修改 + 好题 )

 

这是大白书上的例题,一直放着没有去A掉,这是一道线段树区间修改的好题。

线段树中需要维护三个域 ,max, min, sum,也就是区间最大值,最小值,区间和

 

题目大意:

 

r 行 c 列 的全0矩阵,支持三个操作1 x1 y1 x2 y2 v         子矩阵(x1,y1,x2,y2)的所有元素增加v2 x1 y1 x2 y2 v         子矩阵(x1,y1,x2,y2)的所有元素设为v3 x1 y1 x2 y2           查询子矩阵(x1,y1,x2,y2)的max,sum,min数据范围 0< c <=20  1< m <= 20000

 

 

分析:

可以看到矩阵的行r不超过20,白书上的思路是给每一行建立一个线段树,这样就变为处理一维的线段树了。具体做的时候 3  x1 y1 x2 y2  操作,就对x1 - x2 行分别进行query(),然后sum相加,max和min则做比较就可以了。值得一提的是本题有两个修改操作,一个是add,一个是set这里另外维护了两个标记setv 和 addv。而且它们又先后顺序。可以思考一下,set完之后不管原来是多少, 都变为set之后的值,那么add标记这种东西,也没有必要继续下传了,可以直接清除。1:有两个标记的时候,先处理set,再处理add2:set操作清楚addv标记,但是add操作不清楚setv操作详见代码

 

/* ***********************************************ID      : whiteblock63LANG    : G++PROG    : Uva11992-Fast Matrix OperationDATE    : 2014-10-05 10:34:04************************************************ */#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#define CLR( a, b )        memset( a, b, sizeof(a) )#define ls o << 1#define rs o << 1 | 1#define rt l, r, o#define lson l, m, o << 1#define rson m + 1, r, o << 1 | 1const int NODE_SIZE = 1 << 17;const int INF  = 0x3f3f3f3f;int op, x1, x2, y1, y2, x, v;
// 输入挂inline
void scan( int & x ){ char c; while( c = getchar(), c < 0 || c > 9 ); x = c - 0; while( c = getchar(), c >= 0 && c <= 9 ) x = x*10 + c - 0;}
// 线段树
struct SegTree{ int sumv[NODE_SIZE], minv[NODE_SIZE], maxv[NODE_SIZE]; int setv[NODE_SIZE], addv[NODE_SIZE]; void pushup( int l, int r, int o ){ if( l < r ){ sumv[o] = sumv[ls] + sumv[rs]; minv[o] = min( minv[ls], minv[rs] ); maxv[o] = max( maxv[ls], maxv[rs] ); } if( setv[o] >= 0 ){ minv[o] = maxv[o] = setv[o]; sumv[o] = setv[o] * ( r - l + 1 ); } if( addv[o] ){ minv[o] += addv[o]; maxv[o] += addv[o]; sumv[o] += addv[o] * ( r - l + 1 ); } } void pushdown( int o ){ if( setv[o] >= 0 ){ setv[ls] = setv[rs] = setv[o]; addv[ls] = addv[rs] = 0; setv[o] = -1;  //清除标记 } if( addv[o] ){ addv[ls] += addv[o]; addv[rs] += addv[o]; addv[o] = 0;   //清除标记 } } void update( int l, int r, int o ){ if( y1 <= l && r <= y2 ){ if( op == 1 ) addv[o] += v; else setv[o] = v, addv[o] = 0; }else{ pushdown( o ); int m = l + r >> 1; if( y1 <= m ) update( lson ); else pushup( lson ); if( y2 > m ) update( rson ); else pushup( rson ); } pushup( rt ); } void query( int l, int r, int o, int& ssum, int& smin, int& smax ){ pushup( rt );  // 处理被pushdown下来的标记 if( y1 <= l && r <= y2 ){ ssum = sumv[o]; smin = minv[o]; smax = maxv[o]; }else{ pushdown( o ); int m = l + r >> 1; int lsum = 0, lmin = INF, lmax = -INF; int rsum = 0, rmin = INF, rmax = -INF; if( y1 <= m ) query( lson, lsum, lmin, lmax ); else pushup( lson ); if( y2 > m ) query( rson, rsum, rmin, rmax ); else pushup( rson ); ssum = lsum + rsum; smin = min( lmin, rmin ); smax = max( lmax, rmax ); } }};const int MAXR = 20 + 5;SegTree tree[MAXR];int main(){ int r, c, m; while( ~scanf( "%d %d %d", &r, &c, &m ) ){ CLR( tree, 0 ); for( x = 1; x <= r; ++x ){ CLR( tree[x].setv, -1 ); tree[x].setv[1] = 0; } while( m-- ){ scan( op ); scan( x1 ); scan( y1 ); scan( x2 ); scan( y2 ); if( op < 3 ){ scan( v ); for( x = x1; x <= x2; ++x ) tree[x].update( 1, c, 1 ); }else{ int gsum = 0, gmin = INF, gmax = -INF; for( x = x1; x <= x2; ++x ){ int ssum, smin, smax; tree[x].query( 1, c, 1, ssum, smin, smax ); gsum += ssum; gmin = min( gmin, smin ); gmax = max( gmax, smax ); } printf("%d %d %d\n", gsum, gmin, gmax ); } } } return 0;}

 

UVA11992 - Fast Matrix Operations ( 线段树 + 区间修改 + 好题 )