线段树区间修改


 线段树原理:把区间一分为二,去找到想要的,在查询范围的区间。
//建议去看一下线段树的基本博客

 线段树的真正作用不是单纯数值,而是很好的利用区间信息
 add:运用lasy_tag。记录加的数目而不直接进行更新,而在区间信息里记录。
 set:运用lasy_tag。通过标记记录set值,注意遇到set的大区间直接退回。
 注意在询问的时候利用好这两个信息。

(maintain)维护操作:
  1.遇到标准区间进行标准更新;
  2.遇到set,add在任意区间都赶快修改
(pushdown)下传操作:
  1.在set操作时清楚add
  2.在add操作时直接传
 (update) 直接改标记,注意把改set时清楚add
 (query) 询问:
  1.遇到set的区间,停止询问,
把有(只要占了一个点,见下文的min()-max()+1)查询区间内的那一段返回
  2.遇到查询内的区间,考虑下穿过来的add,标记


//本次操作使用了多颗线段树。树套树更快?等着你!
//本次操作采用刘汝佳的代码风格,确实有工程性和可读性
//这次操作可用了add,set,sum
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#define MM 1<<17
#define rep(i,a,b) for(int i=a; i<=b; ++i)
using namespace std;
int lson(int h) { return h<<1; }
int rson(int h) { return (h<<1)|1;}
int half(int h) { return h>>1; }

int x1, x2, y1, y2, ord , v, _sum , _max, _min;
int r,c,m;

struct Segment_tree 
{
  int addv[MM], setv[MM], minv[MM], maxv[MM], sumv[MM];
  void maintain(int h,int L,int R)
  {
  	int l = lson(h), r = rson(h);
  	if(L<R)
  	{
	  sumv[h] = sumv[l] + sumv[r];
	  maxv[h] = max(maxv[l], maxv[r]);
	  minv[h] = min(minv[l], minv[r]);
	}
	if(setv[h] >=0)
	{
	  minv[h] = maxv[h] = setv[h];
	  sumv[h] = (R-L+1) * setv[h];
	}
	if(addv[h])
	{
	  minv[h] += addv[h];
	  maxv[h] += addv[h];
	  sumv[h] += (R-L+1) * addv[h];
	}
 }
 void pushdown(int h)
  {
    int l = lson(h), r = rson(h);
    if(setv[h] >= 0)
    {
      setv[l] = setv[r] = setv[h];
      addv[l] = addv[r] = 0;
      setv[h] = -1;
	}
	if(addv[h])
	{
	  addv[l] += addv[h];
	  addv[r] += addv[h];
	  addv[h] = 0;
	}
  }
  
  void update(int h,int L,int R)
  {
    int l = lson(h), r = rson(h);
    if(y1 <= L && R <= y2)
    {
      if (ord == 2)
      {
        setv[h] = v;
      	addv[h] = 0;
	  } 
	  else addv[h] += v;
	}
	else
	{
	  pushdown(h);
	  int M = half(L+R);
	  if(y1 <= M) update(l,L,M); else maintain(l,L,M);
	  if(M < y2) update(r,M+1,R); else maintain(r,M+1,R);
	}
	maintain(h,L,R);
  }
  void query(int h,int L,int R,int add)
  {
    if(setv[h] >= 0)
    {
      int k = addv[h] + setv[h] + add;
      _max = max(_max, k);
	  _min = min(_min, k);
	  _sum += k * (min(R,y2)-max(L,y1)+1); 
	}
	else if(y1 <= L && R <= y2)
	{
	  _max = max(_max, add + maxv[h]);
	  _min = min(_min, add + minv[h]);
	  _sum += sumv[h] + add * (R-L+1);
	}
	else
	{
	  int l = lson(h) , r = rson(h);
	  int M = half(L+R);
	  if(y1 <= M) query(l,L,M,add+addv[h]);
	  if(M < y2) query(r,M+1,R,add+addv[h]);
	}
  }
};
struct Segment_tree solver[25];
const int INF = 0x3f3f3f3f;
int main()
{
  while(scanf("%d%d%d",&r,&c,&m)!=EOF)
  {
  	memset(solver,0,sizeof(solver));
  	rep(i,0,r) {memset(solver[i].setv, -1, sizeof(solver[i].setv)); solver[i].setv[1] = 0;}
  	while(m--)
  	{
  	  scanf("%d%d%d%d%d",&ord,&x1,&y1,&x2,&y2);
	  if(ord < 3)
	  {
	    scanf("%d",&v);
		rep(i,x1,x2) solver[i].update(1,1,c);	
	  }	
	  else
	  {
	  	_max = -INF , _min = INF, _sum = 0;
	  	rep(i,x1,x2) solver[i].query(1,1,c,0);
	  	printf("%d %d %d\n",_sum, _min, _max);
	  }
	}
  }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值