P4513 小白逛公园

题目背景

小新经常陪小白去公园玩,也就是所谓的遛狗啦…

题目描述

在小新家附近有一条“公园路”,路的一边从南到北依次排着 nn 个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。

一开始,小白就根据公园的风景给每个公园打了分。小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第 aa 个和第 bb 个公园之间(包括 a, ba,b 两个公园)选择连续的一些公园玩。小白当然希望选出的公园的分数总和尽量高咯。同时,由于一些公园的景观会有所改变,所以,小白的打分也可能会有一些变化。

那么,就请你来帮小白选择公园吧。

输入格式

第一行,两个整数 nn 和 mm,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。

接下来 nn 行,每行一个整数,依次给出小白开始时对公园的打分。

接下来 mm 行,每行三个整数。其中第一个整数 kk 为 11 或 22。

  • k=1k=1 表示,小新要带小白出去玩,接下来的两个整数 aa 和 bb 给出了选择公园的范围 (1 \le a,b \le n)(1≤a,b≤n)。测试数据可能会出现 a > ba>b 的情况,需要进行交换;
  • k=2k=2 表示,小白改变了对某个公园的打分,接下来的两个整数 pp 和 ss,表示小白对第 pp 个公园的打分变成了 s(1\le p\le N)s(1≤p≤N)。

输出格式

小白每出去玩一次,都对应输出一行,只包含一个整数,表示小白可以选出的公园得分和的最大值。

输入输出样例

输入 #1复制

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

输出 #1复制

2
-1

说明/提示

数据规模与约定

对于 100\%100% 的数据,1 \le n \le 5 \times 10^51≤n≤5×105,1 \le m \le 10^51≤m≤105,所有打分都是绝对值不超过 10001000 的整数。

 解题思路:单点修改,区间查询,但这题有意思的是你不能直接简单地将所有范围内区间取max,而是要由子区间推导出来,查询返回一个结构体。

这里维护和sum、最大连续序列值maxn,最大前缀lmax,最大后缀rmax,具体转换见代码

#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
const int N=5e5+5;
class Node{
    public:
        int maxn,lmax,rmax,sum,l,r;
}tree[N<<2];
int arr[N];
void push_up(Node& f,Node& l,Node& r)
{
    f.sum=l.sum+r.sum;
    f.lmax=max(l.sum+r.lmax,l.lmax);
    f.rmax=max(r.sum+l.rmax,r.rmax);
    f.maxn=max(max(l.maxn,r.maxn),l.rmax+r.lmax);
}
void build(int index,ll l,ll r)
{
    tree[index].l=l;tree[index].r=r;
    if(l==r)
    {
        tree[index].sum=arr[l];
        tree[index].lmax=arr[l];
        tree[index].rmax=arr[l];
        tree[index].maxn=arr[l];
        return;
    }
    ll mid=l+r>>1;
    build(index<<1,l,mid);
    build(index<<1|1,mid+1,r);
    push_up(tree[index],tree[index<<1],tree[index<<1|1]);
}
void update(int index,ll k,ll s)
{
    if(tree[index].l==tree[index].r)
    {
        if(tree[index].l!=k)return;
        tree[index].sum=s;
        tree[index].lmax=s;
        tree[index].rmax=s;
        tree[index].maxn=s;
        return;
    }
    int mid=tree[index].l+tree[index].r>>1;
    if(k<=mid)update(index<<1,k,s);
    else update(index<<1|1,k,s);
    push_up(tree[index],tree[index<<1],tree[index<<1|1]);
}
Node query(int index,ll l,ll r)
{
    if(tree[index].l>=l&&tree[index].r<=r)
    {
        return tree[index];
    }
    ll mid=(tree[index].l+tree[index].r)>>1;
    if(mid>=r)return query(index<<1,l,r);//被左区间包含
    else if(mid<l)return query(index<<1|1,l,r);//被右区间包含
    else {
        Node ans,left,right;
        right=query(index<<1|1,l,r);left=query(index<<1,l,r),//否则根据子区间返回结构体信息
        push_up(ans,left,right);
        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,s;
    while(m--)
    {
        cin>>flag;
        if(flag==1)
        {
            cin>>l>>r;
            if(l>r)swap(l,r);
            cout<<query(1,l,r).maxn<<endl;
        }
        else{
            cin>>k>>s;
            update(1,k,s);
        }
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

装B且挨揍の

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值