UVa 11992 Fast Matrix Operations / 线段树成段更新

练基本功 成段更新求2维区间最大值最小值以及和 把某个区间置为v 把某个区间都加上v

难点是set与add的先后顺序的处理

如果先做add在做set那么add是没用的 所以做set时将add置为0

当add不为0 并且 set不为0 那么set肯定在add前面(如果在后面 那么add就置为0了)所以这种情况先做set

当add为0 set不为0 肯定要做set

当add不为0 set为0 做add

都为0(做他干嘛)

所以 按照先set 在add的顺序满足上诉实况

不知小弟理解是否有错

望各位大哥不吝赐教

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 1000010;
struct node
{
	int l;
	int r;
	int max_val;
	int min_val;
	int sum;
	int addv;
	int setv;
};
node a[22][maxn<<2], p; 
void pushup(int i, int rt)
{
	a[i][rt].sum = a[i][rt<<1].sum + a[i][rt<<1|1].sum;
	a[i][rt].max_val = max(a[i][rt<<1].max_val, a[i][rt<<1|1].max_val);
	a[i][rt].min_val = min(a[i][rt<<1].min_val, a[i][rt<<1|1].min_val);
}
void pushdown(int i, int rt)
{
	int k = a[i][rt].r - a[i][rt].l + 1;
	if(a[i][rt].setv != -1)
	{
		a[i][rt<<1].setv = a[i][rt<<1|1].setv = a[i][rt].setv;
		a[i][rt<<1].min_val = a[i][rt<<1|1].min_val = a[i][rt].setv;
		a[i][rt<<1].max_val = a[i][rt<<1|1].max_val = a[i][rt].setv;
		a[i][rt<<1].sum = a[i][rt].setv * (k - (k >> 1));
		a[i][rt<<1|1].sum = a[i][rt].setv * (k >> 1);
		a[i][rt].setv = -1;
		a[i][rt<<1].addv = 0;
		a[i][rt<<1|1].addv = 0;
	}
	if(a[i][rt].addv)
	{
		a[i][rt<<1].addv += a[i][rt].addv;
		a[i][rt<<1].max_val += a[i][rt].addv;
		a[i][rt<<1].min_val += a[i][rt].addv;
		a[i][rt<<1].sum += a[i][rt].addv * (k - (k >> 1));
		
		a[i][rt<<1|1].addv += a[i][rt].addv;
		a[i][rt<<1|1].max_val += a[i][rt].addv;
		a[i][rt<<1|1].min_val += a[i][rt].addv;
		a[i][rt<<1|1].sum += a[i][rt].addv * (k >> 1);
		a[i][rt].addv = 0;
	}	
		
}
void build(int i, int l, int r, int rt)
{
	//printf("%d %d %d %d\n", i, l, r, rt);
	a[i][rt].sum = 0;
	a[i][rt].max_val = 0;
	a[i][rt].min_val = 0;
	a[i][rt].addv = 0;
	a[i][rt].setv = -1;
	a[i][rt].l = l;
	a[i][rt].r = r;
	if(l == r)
		return;
	int m = (l + r) >> 1;
	build(i, l, m, rt<<1);
	build(i, m+1, r, rt<<1|1);
}

void update(int i, int x, int y, int rt, int v, int key)
{
	if(a[i][rt].l == x && a[i][rt].r == y)
	{
		if(key == 1)
		{
			a[i][rt].addv += v;
			a[i][rt].sum += (y-x+1)*v;
			a[i][rt].max_val += v;
			a[i][rt].min_val += v;
		}
		else
		{
			a[i][rt].setv = v;
			a[i][rt].sum = (y-x+1)*v;
			a[i][rt].max_val = v;
			a[i][rt].min_val = v;
			a[i][rt].addv = 0;
		}
		return;	
	}
	//if(a[i][rt].l == a[i][rt].r)
	//	return;
	pushdown(i, rt);
	int m = (a[i][rt].l + a[i][rt].r) >> 1;
	if(y <= m)
		update(i, x, y, rt<<1, v, key);
	else if(x > m)
		update(i, x, y, rt<<1|1, v, key);
	else
	{
		update(i, x, m, rt<<1, v, key);
		update(i, m+1, y, rt<<1|1, v, key);
	}
	pushup(i, rt);
}

void query(int i, int x, int y, int rt)
{
	if(a[i][rt].l == x && a[i][rt].r == y)
	{
		p.sum += a[i][rt].sum;
		p.min_val = min(p.min_val, a[i][rt].min_val);
		p.max_val = max(p.max_val, a[i][rt].max_val);
		return;	
	}
	pushdown(i, rt);
	int m = (a[i][rt].l + a[i][rt].r) >> 1;
	if(y <= m)
		query(i, x, y, rt<<1);
	else if(x > m)
		query(i, x, y, rt<<1|1);
	else
	{
		query(i, x, m, rt<<1);
		query(i, m+1, y, rt<<1|1);
	}
	pushup(i, rt);
}
int main()
{
	int n, m, q;
	while(scanf("%d %d %d", &n, &m, &q) != EOF)
	{
		for(int i = 1; i <= n; i++)
			build(i, 1, m, 1);
		//puts("s");
		/*for(int i = 1; i <= n; ++i)
            for(int j = m << 2; j >= 0; -- j)
                a[i][j].max_val = a[i][j].min_val = a[i][j].addv = a[i][j].sum = 0, a[i][j].setv = -1;*/
		while(q--)
		{
			int k;
			scanf("%d", &k);
			if(k == 1)
			{
				int x1, y1, x2, y2, v;
				scanf("%d %d %d %d %d", &x1, &y1, &x2, &y2, &v);
				for(int i = x1; i <= x2; i++)
					update(i, y1, y2, 1, v, 1);
			}
			else if(k == 2)
			{
				int x1, y1, x2, y2, v;
				scanf("%d %d %d %d %d", &x1, &y1, &x2, &y2, &v);
				for(int i = x1; i <= x2; i++)
					update(i, y1, y2, 1, v, 2);
			}
			else
			{
				int x1, y1, x2, y2;
				scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
				p.sum = 0;
				p.max_val = 0;
				p.min_val = 999999999;
				for(int i = x1; i <= x2; i++)
					query(i, y1, y2, 1);
				printf("%d %d %d\n", p.sum, p.min_val, p.max_val);
			}
		}
	}
	return 0;
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值