线段树 - Can you answer these queries III - SPOJ - GSS3

线段树 - Can you answer these queries III - SPOJ - GSS3

给定长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:

1、“1 x y”,查询区间 [x,y] 中的最大连续子段和,即 m a x x ≤ l ≤ r ≤ y ∑ i = l r A [ i ] max_{x≤l≤r≤y}{∑^r_{i=l}A[i]} maxxlryi=lrA[i]

2、“0 x y”,把 A[x] 改成 y。

对于每个查询指令,输出一个整数表示答案。

输入格式

第一行两个整数N,M。

第二行N个整数A[i]。

接下来M行每行3个整数k,x,y,k=1表示查询(此时如果x>y,请交换x,y),k=0表示修改。

输出格式

对于每个查询指令输出一个整数表示答案。

每个答案占一行。

数据范围

N ≤ 50000 , M ≤ 50000 , ∣ y ∣ ≤ 10000 N≤50000,M≤50000,|y|≤10000 N50000,M50000,y10000

Example

Input:

4
1 2 3 4
4
1 1 3
0 3 -3
1 2 4
1 3 3

Output:

6
4
-3

分析:

单 点 修 改 + 区 间 查 询 。 单点修改+区间查询。 +

对 于 最 大 连 续 子 段 和 , 节 点 结 构 体 中 需 要 存 储 每 个 区 间 的 和 t m a x 。 对于最大连续子段和,节点结构体中需要存储每个区间的和tmax。 tmax

记 总 区 间 为 [ L , R ] , 总 区 间 中 点 m i d = L + R 2 , 则 对 于 被 查 询 区 间 [ l , r ] : 记总区间为[L,R],总区间中点mid=\frac{L+R}{2},则对于被查询区间[l,r]: [L,R]mid=2L+R[l,r]

① 、 若 r ≤ m i d , 则 直 接 在 子 区 间 [ L , m i d ] 中 查 询 区 间 [ l , r ] 内 的 最 大 连 续 子 段 和 。 ①、若r≤mid,则直接在子区间[L,mid]中查询区间[l,r]内的最大连续子段和。 rmid[L,mid][l,r]

② 、 若 l > m i d , 则 直 接 在 子 区 间 [ m i d + 1 , R ] 中 查 询 区 间 [ l , r ] 内 的 最 大 连 续 子 段 和 。 ②、若l>mid,则直接在子区间[mid+1,R]中查询区间[l,r]内的最大连续子段和。 l>mid[mid+1,R][l,r]

③ 、 若 l ≤ m i d ≤ r , 记 区 间 [ l , m i d ] 间 的 最 大 连 续 子 段 和 为 l m a x , 区 间 [ m i d , r ] 间 的 最 大 连 续 子 段 和 为 r m a x , ③、若l≤mid≤r,记区间[l,mid]间的最大连续子段和为lmax,区间[mid,r]间的最大连续子段和为rmax, lmidr[l,mid]lmax[mid,r]rmax

则 区 间 [ l , r ] 内 的 最 大 连 续 子 段 和 为 l m a x + r m a x 。 \qquad则区间[l,r]内的最大连续子段和为lmax+rmax。 [l,r]lmax+rmax

因 此 , 节 点 结 构 体 中 还 需 要 存 储 每 个 区 间 的 l m a x 和 r m a x 。 因此,节点结构体中还需要存储每个区间的lmax和rmax。 lmaxrmax

l m a x : 左 半 区 间 的 最 大 连 续 后 缀 和 ; r m a x : 右 半 区 间 的 最 大 连 续 前 缀 和 。 lmax:左半区间的最大连续后缀和;rmax:右半区间的最大连续前缀和。 lmaxrmax:

新 的 问 题 出 现 了 : 如 何 更 新 l m a x 和 r m a x ? 新的问题出现了:如何更新lmax和rmax? lmaxrmax

① 、 区 间 [ l , r ] 的 最 大 连 续 前 缀 和 为 子 区 间 [ l , r k ] 的 区 间 和 , ①、区间[l,r]的最大连续前缀和为子区间[l,r_k]的区间和, [l,r][l,rk]

Ⅰ 、 若 r k ≤ m i d , 则 l m a x [ l , r k ] = l m a x [ l , m i d ] 。 如 下 图 : \qquadⅠ、若r_k≤mid,则lmax_{[l,r_k]}=lmax_{[l,mid]}。如下图: rkmidlmax[l,rk]=lmax[l,mid]
在这里插入图片描述

Ⅱ 、 若 r k > m i d , 则 l m a x [ l , r ] = s u m [ l , m i d ] + l m a x [ m i d + 1 , r k ] 。 如 下 图 : \qquad Ⅱ、若r_k>mid,则lmax_{[l,r]}=sum_{[l,mid]}+lmax_{[mid+1,r_k]}。如下图: rk>midlmax[l,r]=sum[l,mid]+lmax[mid+1,rk]
在这里插入图片描述

② 、 区 间 [ l , r ] 的 最 大 连 续 后 缀 和 同 理 。 ②、区间[l,r]的最大连续后缀和同理。 [l,r]

于 是 , 节 点 结 构 体 还 需 存 储 区 间 和 s u m 。 s u m 的 更 新 可 直 接 由 左 、 右 子 区 间 得 到 。 于是,节点结构体还需存储区间和sum。sum的更新可直接由左、右子区间得到。 sumsum

代码:

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

using namespace std;

const int N=5e5+10;

struct node
{
    int l,r;
    int sum,lmax,rmax,tmax;
}tr[N*4];

int n,m;
int w[N];

void pushup(node &u,node &l,node &r)
{
    u.sum=l.sum+r.sum;
    u.lmax=max(l.lmax,l.sum+r.lmax);
    u.rmax=max(r.rmax,r.sum+l.rmax);
    u.tmax=max(max(l.tmax,r.tmax),l.rmax+r.lmax);
}

void pushup(int u)
{
    pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}

void build(int u,int l,int r)
{
    if(l==r) tr[u]={r,r,w[r],w[r],w[r],w[r]};
    else
    {
        tr[u]={l,r};
        int mid=l+r>>1;
        build(u<<1,l,mid),build(u<<1|1,mid+1,r);
        pushup(u);
    }
}

node query(int u,int l,int r)
{
    if(l<=tr[u].l&&tr[u].r<=r) return tr[u];
    else
    {
        int mid=tr[u].l+tr[u].r>>1;
        if(r<=mid) return query(u<<1,l,r);   //最大区间和在左侧
        else if(l>mid) return query(u<<1|1,l,r);    //最大区间和在右侧
        else                            //最大区间和跨越两个区间
        {
            node left=query(u<<1,l,r);
            node right=query(u<<1|1,l,r);
            node res;
            pushup(res,left,right);
            return res;
        }
    }
}

void modify(int u,int x,int v)
{
    if(tr[u].l==x&&tr[u].r==x) tr[u]={x,x,v,v,v,v};
    else
    {
        int mid=tr[u].l+tr[u].r>>1;
        if(x<=mid) modify(u<<1,x,v);
        else modify(u<<1|1,x,v);
        pushup(u);
    }
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    build(1,1,n);
    
    scanf("%d",&m);
    int op,x,y;
    while(m--)
    {
        scanf("%d%d%d",&op,&x,&y);
        if(op==1)
        {
            if(x>y) swap(x,y);
            printf("%d\n",query(1,x,y).tmax);
        }
        else modify(1,x,y);
    }
     
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值