题意:有一个r行c列的全0矩阵,支持以下3种操作,如表3-3所示。
□1. x1 y1 x2 y2 v 子矩阵x1 y1 x2 y2的所有元素增加v(v>0)
□2 x1 y1 x2 y2 v 子矩阵x1 y1 x2 y2的所有元素设为v(v>0)
□3 x1 y1 x2 y2 查询子矩阵x1 y1 x2 y2的元素和、最小值和最大值。
子矩阵(x1,y1,x2,y2)是指满足x1≤x≤x2,y1≤y≤y2的所有元素(x,y)。输入保证任意时刻矩阵所有元素之和不超过10^9。
【输入格式】
对于每条类型3的操作,输出3个整数,即该子矩阵的元素和、最小值和最大值。
【分析】
矩阵不超过20行,矩阵元素却可能多达10^6个,可以想到每行建一棵线段树,则本题转化为一维问题。
本题有两个操作,add和set,因此需要两个标记addv和setv,含义同前。规定同时又两个标记时,表示先执行set在执行add。
以上内容来自算法竞赛入门经典训练指南
讲的很清楚了。。。
#include<bits/stdc++.h> using namespace std; const int MaxNode = 1<<17; int _sum, _min, _max, op ,X1, X2, Y1, Y2, v; struct IntervalTree { int sumv[MaxNode], minv[MaxNode], maxv[MaxNode], addv[MaxNode], setv[MaxNode]; //维护信息 void maintain(int o, int L, int R) { int lc = o*2, rc = o*2+1; sumv[o] = minv[o] = maxv[o] = 0; if (R > L) { sumv[o] = sumv[lc] + sumv[rc]; minv[o] = min(minv[lc], minv[rc]); maxv[o] = max(maxv[lc], maxv[rc]); } 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) { int lc = o*2, rc = o*2+1; if(setv[o] >= 0) { setv[lc] = setv[rc] = setv[o]; addv[lc] = addv[rc] = 0; setv[o] = -1; // 清除本结点标记 } if(addv[o]) { addv[lc] += addv[o]; addv[rc] += addv[o]; addv[o] = 0; // 清除本结点标记 } } //更改操作 void update(int o, int L, int R) { int lc = o*2, rc = o*2+1; if (Y1 <= L && R <= Y2) { if (op == 1) addv[o] += v; if (op == 2) { setv[o] = v; addv[o] = 0; } } else { pushdown(o); int M = L + (R-L)/2; if (Y1 <= M) update(lc, L, M); else maintain(lc, L, M); if (Y2 > M) update(rc, M+1, R); else maintain(rc, M+1, R); } maintain(o, L, R); } //查询 void query(int o, int L, int R, int add) { if (setv[o] >= 0) { int v = setv[o] + add + addv[o]; _sum += v * (min(R, Y2)-max(L, Y1)+1); _min = min(_min, v); _max = max(_max, v); return ; } if (Y1 <= L && R <= Y2) { _sum += sumv[o] + add*(R-L+1); _min = min(_min, minv[o] + add); _max = max(_max, maxv[o] + add); return ; } int M = L + (R-L)/2; if (Y1 <= M) query(o*2, L, M, add + addv[o]); if (Y2 > M) query(o*2+1, M+1, R, add + addv[o]); } }; const int MAXR = 20 + 5; const int INF = 1000000000; int r, c, m; IntervalTree tree[MAXR]; int main() { while (~scanf("%d%d%d", &r, &c, &m)) { memset(tree, 0, sizeof(tree)); for (int i = 1; i <= r; i++) { memset(tree[i].setv, -1, sizeof(tree[i].setv)); tree[i].setv[1] = 0; } while (m--) { scanf("%d%d%d%d%d", &op, &X1, &Y1, &X2, &Y2); if (op < 3) { scanf("%d", &v); for (int i = X1; i <= X2; i++) tree[i].update(1, 1, c); } else { _sum = 0; _min = INF; _max = -INF; for (int i = X1; i <= X2; i++) tree[i].query(1, 1, c, 0); printf("%d %d %d\n", _sum, _min, _max); } } } return 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 */