刘汝佳白书上的题目。
题意 : 给你一个矩阵(m * n,最多20行,总元素不超过10^6个),然后Q次操作。有3种操作 :
1,在(x1,y1)~(x2,y2)这个子矩阵上每一个元素都加上 v。
2,在(x1,y1)~(x2,y2)把这个子矩阵上的每一个元素都变为v。
3,询问(x1,y1)~(x2,y2)这个子矩阵的总和,最小值,最大值。
思路 : 因为最多20行,所以开20个线段树来更新和询问操作。然后就是一维区间更新问题了。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 100005;
const int INF = 900000005;
#define lson e, rt<<1, l, mid
#define rson e, rt<<1|1, mid+1, r
int MAX(int a, int b){return a > b ? a : b;}
int MIN(int a, int b){return a < b ? a : b;}
struct Get
{
int Max, Min, Sum;
};
int msum[22][maxn<<2], mmin[22][maxn<<2], mmax[22][maxn<<2], addv[22][maxn<<2], setv[22][maxn<<2];
int n, m, Q;
void pushdown(int rt, int e, int M)
{
if (setv[e][rt])
{
msum[e][rt<<1] = setv[e][rt] * (M - (M>>1));
msum[e][rt<<1|1] = setv[e][rt] * (M>>1);
setv[e][rt<<1] = setv[e][rt<<1|1] = setv[e][rt];
mmax[e][rt<<1] = mmax[e][rt<<1|1] = setv[e][rt];
mmin[e][rt<<1] = mmin[e][rt<<1|1] = setv[e][rt];
setv[e][rt] = addv[e][rt<<1] = addv[e][rt<<1|1] = 0;
}
if (addv[e][rt])
{
msum[e][rt<<1] += addv[e][rt] * (M - (M>>1)); msum[e][rt<<1|1] += addv[e][rt] * (M>>1);
mmin[e][rt<<1] += addv[e][rt]; mmax[e][rt<<1] += addv[e][rt];
mmin[e][rt<<1|1] += addv[e][rt]; mmax[e][rt<<1|1] += addv[e][rt];
addv[e][rt<<1] += addv[e][rt]; addv[e][rt<<1|1] += addv[e][rt];
addv[e][rt] = 0;
}
}
void pushup(int rt, int e, int M)
{
msum[e][rt] = msum[e][rt<<1] + msum[e][rt<<1|1];
mmax[e][rt] = MAX(mmax[e][rt<<1], mmax[e][rt<<1|1]);
mmin[e][rt] = MIN(mmin[e][rt<<1], mmin[e][rt<<1|1]);
}
void build(int e, int rt, int l, int r)
{
addv[e][rt] = 0;
setv[e][rt] = 0;
if (l == r)
{
msum[e][rt] = mmin[e][rt] = mmax[e][rt] = 0;
return ;
}
int mid = (l + r) >> 1;
build(lson); build(rson);
pushup(rt, e, r - l + 1);
}
void update(int e, int rt, int l, int r, int L, int R, int col, int op)
{
if (l >= L && r <= R)
{
if (op == 1)
{
msum[e][rt] += (r - l + 1) * col;
mmin[e][rt] += col;
mmax[e][rt] += col;
addv[e][rt] += col;
}
else
{
addv[e][rt] = 0;
msum[e][rt] = (r - l + 1) * col;
mmax[e][rt] = mmin[e][rt] = col;
setv[e][rt] = col;
}
return ;
}
pushdown(rt, e, r - l + 1);
int mid = (l + r) >> 1;
if (mid >= L)update(lson, L, R, col, op);
if (R > mid) update(rson, L, R, col, op);
pushup(rt, e, r - l + 1);
}
Get query(int e, int rt, int l, int r, int L, int R)
{
Get res, tt;
if (l >= L && r <= R)
{
res.Max = mmax[e][rt];
res.Min = mmin[e][rt];
res.Sum = msum[e][rt];
return res;
}
pushdown(rt, e, r - l + 1);
int mid = (l + r) >> 1;
res.Sum = 0; res.Max = -INF; res.Min = INF;
if (mid >= L)
{
tt = query(lson, L, R);
res.Sum += tt.Sum;
res.Max = MAX(res.Max, tt.Max);
res.Min = MIN(res.Min, tt.Min);
}
if (R > mid)
{
tt = query(rson, L, R);
res.Sum += tt.Sum;
res.Max = MAX(res.Max, tt.Max);
res.Min = MIN(res.Min, tt.Min);
}
return res;
}
int main()
{
int i;
while (scanf("%d%d%d",&m,&n,&Q) == 3)
{
for (i = 1;i <= m;i++)
{
build(i, 1, 1, n);
}
while (Q--)
{
int op, x1, x2, y1, y2, v;
scanf("%d%d%d%d%d", &op, &x1, &y1, &x2, &y2);
if (op == 1)
{
scanf("%d", &v);
for (i = x1;i <= x2;i++)
{
update(i, 1, 1, n, y1, y2, v, 1);
}
}
else if (op == 2)
{
scanf("%d", &v);
for (i = x1;i <= x2;i++)
{
update(i, 1, 1, n, y1, y2, v, 2);
}
}
else if (op == 3)
{
int Min = INF, Max = -INF, ans = 0;
Get res;
for (i = x1;i <= x2;i++)
{
res = query(i, 1, 1, n, y1, y2);
Min = MIN(Min, res.Min);
Max = MAX(Max, res.Max);
ans += res.Sum;
}
printf("%d %d %d\n", ans, Min, Max);
}
else printf("BUG!!!!\n");
}
}
return 0;
}