UVA 11992 Fast Matrix Operations (线段树区间更新)

刘汝佳白书上的题目。

题意 : 给你一个矩阵(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;
}


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值