uva11992 Fast Matrix Operations (线段树)

题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18697

题意:给定N*M的矩阵,初始值为0。有三种操作①将x1~x2行的y1~y2列的值加v(v>0)②将x1~x2行的y1~y2列的值改为v(v>0)③查询x1~x2行的y1~y2列里面的所有值的和,以及其中的最小值和最大值。(N<=20)

分析:由于N<20,只需维护N棵线段树就行了。我开始写的代码虽然A了,但是感觉不怎么好。后来又写了一个版本。


开始的版本:每次更新的时候只把当前区间的懒惰标记修改一下,本身的最大最小值以及和都没有更新,pushdown的时候也只把懒惰标记传递下去,所以查询的时候当前区间还要把左右孩子的信息传递上来。感觉有点危险。以后还是不要这样写。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 1e6+6;
int _max,_min,_sum;
struct node
{
	int setv,addv;
	int Max,Min,Sum;
};
struct segtree
{
	node tree[maxn<<2];
	void build(int l,int r,int rt)
	{
		tree[rt].addv=tree[rt].Max=tree[rt].Min=tree[rt].setv=tree[rt].Sum=0;
		if(l==r)
			return ;
		int m=(l+r)>>1;
		build(lson);
		build(rson);
	}
	void pushdown(int rt)
	{
		if(tree[rt].setv>0)
		{
			tree[rt<<1].setv=tree[rt<<1|1].setv=tree[rt].setv;
			tree[rt<<1].addv=tree[rt<<1|1].addv=tree[rt].setv=0;
		}
		if(tree[rt].addv>0)
		{
			tree[rt<<1].addv+=tree[rt].addv;
			tree[rt<<1|1].addv+=tree[rt].addv;
			tree[rt].addv=0;
		}
	}
	void pushup(int l,int r,int rt)
	{
		int m=(l+r)>>1,lmax,lmin,lsum,rmax,rmin,rsum;
		lmax=tree[rt<<1].addv+tree[rt<<1].Max;
		lmin=tree[rt<<1].addv+tree[rt<<1].Min;
		lsum=tree[rt<<1].Sum+tree[rt<<1].addv*(m-l+1);
		rmax=tree[rt<<1|1].addv+tree[rt<<1|1].Max;
		rmin=tree[rt<<1|1].addv+tree[rt<<1|1].Min;
		rsum=tree[rt<<1|1].Sum+tree[rt<<1|1].addv*(r-m);
		
		if(tree[rt<<1].setv>0)
		{
			lmax=lmin=tree[rt<<1].setv+tree[rt<<1].addv;
			lsum=(tree[rt<<1].setv+tree[rt<<1].addv)*(m-l+1);
		}
		if(tree[rt<<1|1].setv>0)
		{
			rmax=rmin=tree[rt<<1|1].setv+tree[rt<<1|1].addv;
			rsum=(tree[rt<<1|1].setv+tree[rt<<1|1].addv)*(r-m);
		}
		tree[rt].Max=max(lmax,rmax);
		tree[rt].Min=min(lmin,rmin);
		tree[rt].Sum=lsum+rsum;
	}
	void update_add(int L,int R,int v,int l,int r,int rt)
	{
		if(L<=l && r<=R)
		{
			tree[rt].addv+=v;
			return ;
		}
		pushdown(rt);
		int m=(l+r)>>1;
		if(L<=m)
			update_add(L,R,v,lson);
		if(R>m)
			update_add(L,R,v,rson);
		pushup(l,r,rt);
	}
	void update_set(int L,int R,int v,int l,int r,int rt)
	{
		if(L<=l && r<=R)
		{
			tree[rt].addv=0;
			tree[rt].setv=v;
			return ;
		}
		pushdown(rt);
		int m=(l+r)>>1;
		if(L<=m)
			update_set(L,R,v,lson);
		if(R>m)
			update_set(L,R,v,rson);
		pushup(l,r,rt);
	}
	void query(int L,int R,int l,int r,int rt)
	{
		if(L<=l && r<=R)
		{
			pushdown(rt);
			pushup(l,r,rt);
			if(tree[rt].Max>_max)
				_max=tree[rt].Max;
			if(tree[rt].Min<_min)
				_min=tree[rt].Min;
			_sum+=tree[rt].Sum;
			return ;
		}
		pushdown(rt);
		int m=(l+r)>>1;
		if(L<=m)
			query(L,R,lson);
		if(R>m)
			query(L,R,rson);
		pushup(l,r,rt);
	}
}T[22];

int main()
{
	int N,n,q,tp,L,R,v,x,y;
	while(scanf("%d%d%d",&N,&n,&q)!=EOF)
	{
		for(int i=0;i<=N;i++)
			T[i].build(1,n,1);
		while(q--)
		{
			scanf("%d",&tp);
			if(tp==1)
			{
				scanf("%d%d%d%d%d",&x,&L,&y,&R,&v);
				for(int i=x;i<=y;i++)
					T[i].update_add(L,R,v,1,n,1);
			}
			else if(tp==2)
			{
				scanf("%d%d%d%d%d",&x,&L,&y,&R,&v);
				for(int i=x;i<=y;i++)
					T[i].update_set(L,R,v,1,n,1);
			}
			else
			{
				_min=2e9;
				_max=-_min;
				_sum=0;
				scanf("%d%d%d%d",&x,&L,&y,&R);
				for(int i=x;i<=y;i++)
					T[i].query(L,R,1,n,1);
				printf("%d %d %d\n",_sum,_min,_max);
			}
		}
	}
	return 0;
}

后来的版本,更新的时候把当前区间的所有信息都更新了,pushdown的时候把左右孩子的所有信息更新了。所以查询的时候直接用当前区间的信息。

代码:

#include <iostream>
#include <cstdio>

using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 1e6+6;
int _min,_max,_sum;
struct node
{
	int addv,setv;
	int Max,Min,Sum;
};
struct segtree
{
	node tree[maxn<<2];	
	void pushdown(int l,int r,int rt)
	{
		int m=(l+r)>>1;
		if(tree[rt].setv>0)
		{
			tree[rt<<1].Max=tree[rt<<1|1].Max=tree[rt<<1].Min=tree[rt<<1|1].Min=tree[rt<<1].setv=tree[rt<<1|1].setv=tree[rt].setv;
			tree[rt<<1].Sum=tree[rt].setv*(m-l+1);
			tree[rt<<1|1].Sum=tree[rt].setv*(r-m);
			tree[rt<<1].addv=tree[rt<<1|1].addv=tree[rt].setv=0;
		}
		if(tree[rt].addv>0)
		{
			tree[rt<<1].addv+=tree[rt].addv;
			tree[rt<<1].Max+=tree[rt].addv;
			tree[rt<<1].Min+=tree[rt].addv;
			tree[rt<<1].Sum+=tree[rt].addv*(m-l+1);
			
			tree[rt<<1|1].addv+=tree[rt].addv;
			tree[rt<<1|1].Max+=tree[rt].addv;
			tree[rt<<1|1].Min+=tree[rt].addv;
			tree[rt<<1|1].Sum+=tree[rt].addv*(r-m);
			tree[rt].addv=0;
		}
	}
	void pushup(int rt)
	{
		tree[rt].Max=max(tree[rt<<1].Max,tree[rt<<1|1].Max);
		tree[rt].Min=min(tree[rt<<1].Min,tree[rt<<1|1].Min);
		tree[rt].Sum=tree[rt<<1].Sum+tree[rt<<1|1].Sum;
	}
	void build(int l,int r,int rt)
	{
		tree[rt].Max=tree[rt].Min=tree[rt].addv=tree[rt].setv=tree[rt].Sum=0;
		if(l==r)
			return ;
		int m=(l+r)>>1;
		build(lson);
		build(rson);
	}
	void update_add(int L,int R,int v,int l,int r,int rt)
	{
		if(L<=l && r<=R)
		{
			tree[rt].addv+=v;
			tree[rt].Sum+=v*(r-l+1);
			tree[rt].Max+=v;
			tree[rt].Min+=v;
			return ;
		}
		pushdown(l,r,rt);
		int m=(l+r)>>1;
		if(L<=m)
			update_add(L,R,v,lson);
		if(R>m)
			update_add(L,R,v,rson);
		pushup(rt);
	}
	void update_set(int L,int R,int v,int l,int r,int rt)
	{
		if(L<=l && r<=R)
		{
			tree[rt].addv=0;
			tree[rt].setv=v;
			tree[rt].Sum=v*(r-l+1);
			tree[rt].Max=v;
			tree[rt].Min=v;
			return ;
		}
		pushdown(l,r,rt);
		int m=(l+r)>>1;
		if(L<=m)
			update_set(L,R,v,lson);
		if(R>m)
			update_set(L,R,v,rson);
		pushup(rt);
	}
	void query(int L,int R,int l,int r,int rt)
	{
		if(L<=l && r<=R)
		{
			_sum+=tree[rt].Sum;
			if(tree[rt].Min<_min)
				_min=tree[rt].Min;
			if(tree[rt].Max>_max)
				_max=tree[rt].Max;
			return ;
		}
		pushdown(l,r,rt);
		int m=(l+r)>>1;
		if(L<=m)
			query(L,R,lson);
		if(R>m)
			query(L,R,rson);
		pushup(rt);
	}
}T[22];
int main()
{
	int N,n,q,tp,L,R,v,x,y;
	while(scanf("%d%d%d",&N,&n,&q)!=EOF)
	{
		for(int i=0;i<=N;i++)
			T[i].build(1,n,1);
		while(q--)
		{
			scanf("%d",&tp);
			if(tp==1)
			{
				scanf("%d%d%d%d%d",&x,&L,&y,&R,&v);
				for(int i=x;i<=y;i++)
					T[i].update_add(L,R,v,1,n,1);
			}
			else if(tp==2)
			{
				scanf("%d%d%d%d%d",&x,&L,&y,&R,&v);
				for(int i=x;i<=y;i++)
					T[i].update_set(L,R,v,1,n,1);
			}
			else
			{
				_min=2e9;
				_max=-_min;
				_sum=0;
				scanf("%d%d%d%d",&x,&L,&y,&R);
				for(int i=x;i<=y;i++)
					T[i].query(L,R,1,n,1);
				printf("%d %d %d\n",_sum,_min,_max);
			}
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值