UVa 11992 add与set结合区间修改线段树

差点忘记还有这么一个线段树的题目,白书上的最后一个例题了,也是足见其难度啊,和一般的题目就是不一样,这个需要考虑的是set和add两种情况同时存在的情况了,这个需要考虑的就是当add先在某一段区间标记了,那么如果下一次当该区间又标记了set的话,实际上前面做到add就没用了,可以直接被抹去了,而如果在set之后又来了一次的set的话,那样的话两者都需要保留下来,那么难点就来了,在pushdown这里的话,肯定需要先判读set标记了,如果set存在的话那么对其左右子树进行各种操作了,特别的需要对左右子节点的add标志要清零,因为下面对左右子节点的set要进行操作了那就和前面说道的一样,set出现,那么之前的add都不算数了,其他的各种指标只要合理操作即可了。

这题还是有点难度的,参考了这篇博文:http://blog.csdn.net/a601025382s/article/details/38356535

还有就是我的这里的代码的写法不如上面博客的,因为写惯了不是结构体的写法,在这个多指标的情况下,其实还是一开始就直接写结构体会来的更加方便一些。

#include<cstdio>
#include<cstring>
#include<algorithm>


using namespace std;

#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define mid int m = (l + r)>>1
const int maxn=10e6+5;
int r,c,m,tag,x1,x2,y1,y2,v;
int adds[maxn<<2],sets[maxn<<2],sum[maxn<<2],maxs[maxn<<2],mins[maxn<<2];
struct node
{
    int sum,maxs,mins;
};

void build(int l,int r,int rt)
{
    adds[rt]=sets[rt]=sum[rt]=maxs[rt]=mins[rt]=0;
    if(l==r)
        return ;
    mid;
    build(lson);
    build(rson);
}

void pushdown(int l,int r,int rt)
{
    if(sets[rt]!=0)//当有两个标记时,必定是add要在set之后做的
    {
      adds[rt*2]=adds[rt*2+1]=0;
      sets[rt*2]=sets[rt*2+1]=sets[rt];
      mins[rt*2]=mins[rt*2+1]=maxs[rt*2]=maxs[rt*2+1]=sets[rt];
       mid;
      sum[rt*2]=(m-l+1)*sets[rt];
      sum[rt*2+1]=(r-m)*sets[rt];
      sets[rt]=0;
    }
    if(adds[rt]!=0)
    {
        adds[rt*2]+=adds[rt];
        adds[rt*2+1]+=adds[rt];
        maxs[rt*2]+=adds[rt];
        maxs[rt*2+1]+=adds[rt];
        mins[rt*2]+=adds[rt];
        mins[rt*2+1]+=adds[rt];
        mid;
        sum[rt*2]+=(m-l+1)*adds[rt];
        sum[rt*2+1]+=(r-m)*adds[rt];
        adds[rt]=0;
    }
}

void update_add(int l,int r,int rt,int x,int y,int z)
{
    if(x<=l&&y>=r)
    {
        adds[rt]+=z;
        maxs[rt]+=z;
        mins[rt]+=z;
        sum[rt]+=(r-l+1)*z;
        return ;
    }
    mid;
    pushdown(l,r,rt);
    if(x<=m) update_add(lson,x,y,z);
    if(y>m) update_add(rson,x,y,z);
    maxs[rt]=max(maxs[rt*2],maxs[rt*2+1]);
    mins[rt]=min(mins[rt*2],mins[rt*2+1]);
    sum[rt]=sum[rt*2]+sum[rt*2+1];
}

void update_set(int l,int r,int rt,int x,int y,int z)
{
    if(x<=l&&y>=r)
    {
        adds[rt]=0;//因为置位set的优先级肯定要高啊,因为不管先前add了多少的值在这段区间,如果只要出现了一次的set那么值都是set放的z值
        sets[rt]=z;
        maxs[rt]=z;
        mins[rt]=z;
        sum[rt]=(r-l+1)*z;
        return ;
    }
    pushdown(l,r,rt);
    mid;
    if(x<=m) update_set(lson,x,y,z);
    if(y>m) update_set(rson,x,y,z);
    maxs[rt]=max(maxs[rt*2],maxs[rt*2+1]);
    mins[rt]=min(mins[rt*2],mins[rt*2+1]);
    sum[rt]=sum[rt*2]+sum[rt*2+1];
}

node query(int l,int r,int rt,int x,int y)
{
    if(x<=l&&y>=r)
    {
        node tmp;
        tmp.maxs=maxs[rt];
        tmp.mins=mins[rt];
        tmp.sum=sum[rt];
        return tmp;
    }
    pushdown(l,r,rt);
    mid;
    node t;
    if(y<=m) return query(lson,x,y);
    else if(x>m) return query(rson,x,y);
    else
    {
      node p,q;
      p=query(lson,x,y);
      q=query(rson,x,y);
      t.sum=p.sum+q.sum;
      t.maxs=max(p.maxs,q.maxs);
      t.mins=min(p.mins,q.mins);
        return t;
    }
}

int main()
{
    while(scanf("%d%d%d",&r,&c,&m)!=EOF)
    {
        build(1,r*c,1);
     while(m--)
     {
         scanf("%d%d%d%d%d",&tag,&x1,&y1,&x2,&y2);
         if(tag==3)
         {
             node ans,p;
            for(int i=x1;i<=x2;i++)
            {
                if(i==x1)
                    ans=query(1,r*c,1,(i-1)*c+y1,(i-1)*c+y2);
                else
                {
                    p=query(1,r*c,1,(i-1)*c+y1,(i-1)*c+y2);
                    ans.sum+=p.sum;
                    ans.maxs=max(ans.maxs,p.maxs);
                    ans.mins=min(ans.mins,p.mins);
                }
            }
            printf("%d %d %d\n",ans.sum,ans.mins,ans.maxs);
         }
         else if(tag==2)
         {
          scanf("%d",&v);
          for(int i=x1;i<=x2;i++)
          update_set(1,r*c,1,(i-1)*c+y1,(i-1)*c+y2,v);
         }
         else if(tag==1)
         {
          scanf("%d",&v);
          for(int i=x1;i<=x2;i++)
          update_add(1,r*c,1,(i-1)*c+y1,(i-1)*c+y2,v);
         }
     }
    }
    return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值