洛谷P1253 扶苏的问题(区间加值,区间修改,求区间max)
题目
Description
给定一个长度为 nn 的序列 aa,要求支持如下三个操作:
- 给定区间 [l,r][l,r],将区间内每个数都修改为 xx。
- 给定区间 [l,r][l,r],将区间内每个数都加上 xx。
- 给定区间 [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; }