P1253 扶苏的问题

题目描述

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

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

输入格式

第一行是两个整数,依次表示序列的长度 nn 和操作的个数 qq。
第二行有 nn 个整数,第 ii 个整数表示序列中的第 ii 个数 a_iai​。
接下来 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] 内的最大值。

输出格式

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

输入输出样例

输入 #1复制

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

输出 #1复制

7
6
-1

输入 #2复制

4 4
10 4 -3 -7
1 1 3 0
2 3 4 -4
1 2 4 -9
3 1 4

输出 #2复制

0

说明/提示

数据规模与约定

  • 对于 10\%10% 的数据,n = q = 1n=q=1。
  • 对于 40\%40% 的数据,n, q \leq 10^3n,q≤103。
  • 对于 50\%50% 的数据,0 \leq a_i, x \leq 10^40≤ai​,x≤104。
  • 对于 60\%60% 的数据,op \neq 1op=1。
  • 对于 90\%90% 的数据,n, q \leq 10^5n,q≤105。
  • 对于 100\%100% 的数据,1 \leq n, q \leq 10^61≤n,q≤106,1 \leq l, r \leq n1≤l,r≤n,op \in \{1, 2, 3\}op∈{1,2,3},|a_i|, |x| \leq 10^9∣ai​∣,∣x∣≤109。

提示

请注意大量数据读入对程序效率造成的影响。

解题思路,对于 修改为x和加上x,可以统一为乘a加b,修改时,a为0,b为x,增加时,a为1,b为x,在线段树中维护a,b和最大值即可。当pushdown时,由于(val*a0+b0)*a1+b1=val*a0*a1+b0*a1+b1,用父区间的a1,b1来更新子区间的a0,b0。

#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
const int N=1e6+5;
class Node{
    public:
        ll maxn,a,b;
        ll l,r;
}tree[N<<2];
ll arr[N];
void build(int index,ll l,ll r)
{
    tree[index].l=l;tree[index].r=r;
    tree[index].a=1;tree[index].b=0;
    if(l==r)
    {
        tree[index].maxn=arr[l];
        return;
    }
    ll mid=l+r>>1;
    build(index<<1,l,mid);
    build(index<<1|1,mid+1,r);
    tree[index].maxn=max(tree[index<<1].maxn,tree[index<<1|1].maxn);
}
void push_down(int index)
{
    if(tree[index].a==1&&tree[index].b==0)return;
    tree[index<<1].a*=tree[index].a;
    tree[index<<1].b=tree[index<<1].b*tree[index].a+tree[index].b;
    tree[index<<1].maxn=tree[index<<1].maxn*tree[index].a+tree[index].b;
    tree[index<<1|1].a*=tree[index].a;
    tree[index<<1|1].b=tree[index<<1|1].b*tree[index].a+tree[index].b;
    tree[index<<1|1].maxn=tree[index<<1|1].maxn*tree[index].a+tree[index].b;
    tree[index].a=1;tree[index].b=0;
}
void update(int index,ll l,ll r,ll x,ll y)
{
    if(tree[index].l>=l&&tree[index].r<=r)
    {
        tree[index].a*=x;tree[index].b=tree[index].b*x+y;
        tree[index].maxn=tree[index].maxn*x+y;
        return;
    }
    push_down(index);
    if(tree[index<<1].r>=l)update(index<<1,l,r,x,y);
    if(tree[index<<1|1].l<=r)update(index<<1|1,l,r,x,y);
    tree[index].maxn=max(tree[index<<1].maxn,tree[index<<1|1].maxn);
}
ll query(int index,ll l,ll r)
{
    if(tree[index].l>=l&&tree[index].r<=r)
    {
        return tree[index].maxn;
    }
    push_down(index);
    ll ans=-1e18;
    if(tree[index<<1].r>=l)ans=max(ans,query(index<<1,l,r));
    if(tree[index<<1|1].l<=r)ans=max(ans,query(index<<1|1,l,r));
    return ans;
}
int main( )
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    ll n;cin>>n;ll m;cin>>m;
    for(int i=1;i<=n;i++)cin>>arr[i];
    build(1,1,n);
    ll flag,l,r,K;
    while(m--)
    {
        cin>>flag;
        if(flag==1)
        {
            cin>>l>>r>>K;
            update(1,l,r,0,K);
        }
        else if(flag==2)
        {
            cin>>l>>r>>K;
            update(1,l,r,1,K);
        }
        else{
            cin>>l>>r;
            cout<<query(1,l,r)<<endl;
        }
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值