题意:有一个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
*/