*点击

洛谷P1253 扶苏的问题(区间加值,区间修改,求区间max)

题目

Description

给定一个长度为 nn 的序列 aa,要求支持如下三个操作:

  1. 给定区间 [l,r][l,r],将区间内每个数都修改为 xx。
  2. 给定区间 [l,r][l,r],将区间内每个数都加上 xx。
  3. 给定区间 [l,r][l,r],求区间内的最大值。

Input

第一行是两个整数,依次表示序列的长度 nn 和操作的个数 qq。
第二行有 nn 个整数,第 ii 个整数表示序列中的第 ii 个数 aiai
接下来 qq 行,每行表示一个操作。每行首先有一个整数 opop,表示操作的类型。

    • 若 op=1op=1,则接下来有三个整数 l,r,xl,r,x,表示将区间 [l,r][l,r] 内的每个数都修改为 xx。
    • 若 op=2op=2,则接下来有三个整数 l,r,xl,r,x,表示将区间 [l,r][l,r] 内的每个数都加上 xx。
    • 若 op=3op=3,则接下来有两个整数 l,rl,r,表示查询区间 [l,r][l,r] 内的最大值。

Output

对于每个 op=3op=3 的操作,输出一行一个整数表示答案。

Sample Input

6 6
1 1 4 5 1 4
1 1 2 6
2 3 4 2
3 1 4
3 2 3
1 1 6 -1
3 1 6

Sample Output

7
6
-1

思路

两种操作区间加上一个数和区间修改;

所以我们要使用两种lazy标记;

 

考虑两种操作的情况;

区间加在需要打上lazy标记时;

判断区间是否存在修改标记;

若存在修改标记;

因为修改标记还没下传;

可以把 加标记 清零,修改标记加上 加标记 的值;

区间修改时需要打上lazy标记时;

因为该区间需要修改,之前的 加标记 就都不用考虑了;

就将 加标记 清零,附上修改标记;

 

有个要注意的地方,因为题目可以有负数;

如果要把区间修改为 $0$ 且修改标记未附初始值(一开始为都$0$),就会出现没有修改的情况;

所以 修改标记 的初始值要附一个题目数值以外的值;

 

代码

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const ll _=5e6;
const ll minn=LONG_LONG_MIN;
ll n,m;
ll v[_];
struct tree
{
    ll l,r,v,f,ff=minn;//f为加标记,ff为修改标记
}a[_];
void build(ll p,ll l,ll r)//建树
{
    a[p].l=l; a[p].r=r;
    if(l==r)
    {
        a[p].v=v[l];
        return;
    }
    ll mid=(l+r)>>1;
    ll ls=2*p,rs=2*p+1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    a[p].v=max(a[ls].v,a[rs].v);
}
inline void pushdown(ll p)
{
    if(a[p].f)
    {
        ll ls=p*2,rs=p*2+1;
        a[ls].v+=a[p].f;
        a[rs].v+=a[p].f;
        if(a[ls].ff!=minn)//如果存在修改标记,把修改标记加上 加标记 的值
            a[ls].ff+=a[p].f;
        else//否则 加标记 下传
            a[ls].f+=a[p].f;
        if(a[rs].ff!=minn)//同上
            a[rs].ff+=a[p].f;            
        else
            a[rs].f+=a[p].f;
        a[p].f=0;
    }
    if(a[p].ff!=minn)
    {
        ll ls=p*2,rs=p*2+1;
        a[ls].v=a[p].ff;
        a[rs].v=a[p].ff;
        a[ls].ff=a[p].ff;//下传 修改标记
        a[rs].ff=a[p].ff;
        a[p].ff=minn;
        a[ls].f=a[rs].f=0;//修改后,之前的 加标记 都无需考虑
    }
}
void update(ll p,ll l,ll r,ll val)
{
    if(l<=a[p].l&&a[p].r<=r)
    {
        a[p].v+=val;
        if(a[p].ff!=minn)//如果存在修改标记,把修改标记加上 加标记 的值
            a[p].ff+=val;
        else//否则打上 加标记
            a[p].f+=val;
        return;
    }
    pushdown(p);
    ll mid=(a[p].l+a[p].r)>>1;
    ll ls=2*p,rs=2*p+1;
    if(l<=mid)
        update(ls,l,r,val);
    if(r>mid)
        update(rs,l,r,val);
    a[p].v=max(a[ls].v,a[rs].v);
}
void change(ll p,ll l,ll r,ll x)
{
    if(l<=a[p].l&&a[p].r<=r)
    {
        a[p].v=x;
        a[p].ff=x;
        a[p].f=0;//修改后,之前 加标记 清零
        return;
    }
    pushdown(p);
    ll mid=(a[p].l+a[p].r)>>1;
    ll ls=2*p,rs=2*p+1;
    if(l<=mid)
        change(ls,l,r,x);
    if(r>mid)
        change(rs,l,r,x);
    a[p].v=max(a[ls].v,a[rs].v);
}
ll findout(ll p,ll l,ll r)
{
    if(l<=a[p].l&&a[p].r<=r)
        return a[p].v;
    pushdown(p);
    ll ans=minn;
    ll mid=(a[p].l+a[p].r)>>1;
    ll ls=2*p,rs=2*p+1;
    if(l<=mid)
        ans=max(ans,findout(ls,l,r));
    if(r>mid)
        ans=max(ans,findout(rs,l,r));
    return ans;
}
int main()
{
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=n;i++)
        scanf("%lld",&v[i]);
    build(1,1,n);
    for(ll i=1;i<=m;i++)
    {
        ll num,x,y,z;
        scanf("%lld%lld%lld",&num,&x,&y);
        if(num==1)
        {
            scanf("%lld",&z);
            change(1,x,y,z);
        }
        if(num==2)
        {
            scanf("%lld",&z);
            update(1,x,y,z);
        }
        if(num==3)
            printf("%lld\n",findout(1,x,y));
    }
    return 0;
}

 

 

posted @ 2024-11-24 23:12  木偶人-怪咖  阅读(4)  评论(0编辑  收藏  举报
*访客位置3D地图 *目录