SPOJ 1043 GSS1 & 1716 GSS3 Can you answer these queries 线段树

$ \Rightarrow $ 戳我看GSS1原题 $ \Rightarrow $ 戳我看GSS3原题
 

SP1043 GSS1 - Can you answer these queries I

时空限制 $ \quad $ 230ms / 1536MB

题目描述

给出了序列 $ A[1],A[2],…,A[N] $ 。$ (a[i]≤15007,1≤N≤50000) $ 。
查询定义如下: 查询 $ (x,y)=max{a[i]+a[i+1]+...+a[j];x≤i≤j≤y} $ 。
给定 $ M $ 个查询,程序必须输出这些查询的结果。
 

输入输出格式

输入格式

输入文件的第一行包含整数 $ N $ 。
在第二行,$ N $ 个数字跟随。
第三行包含整数 $ M $ 。
$ M $ 行跟在后面,其中第 $ 1 $ 行包含两个数字 $ x_i $ 和 $ y_i $ 。

输出格式

您的程序应该输出M查询的结果,每一行一个查询。

感谢@何高琛 提供的翻译
 

输入输出样例

输入样例
 3 
 -1 2 3
 1
 1 2
输出样例
 2

SP1716 GSS3 - Can you answer these queries III

时空限制 $ \quad $ 330ms / 1536MB

题意翻译

$ n $ 个数,$ q $ 次操作
操作0 x y把 $ A_x $ 修改为 $ y $
操作1 l r询问区间 $ [l, r] $ 的最大子段和

感谢 @Edgration 提供的翻译
 

题解

  • 线段树上维护4个值得信息

    • 区间和sum
      最大子段和dat
      左端开始得最大子段和lmax
      右端开始的最大子段和rmax
  • 合并的时候略麻烦
     

GSS3代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 50010
#define int long long
struct tree{ int l,r,lmax,rmax,max,sum; }t[maxn<<2];
int n,m,l,r,opt;
void pushup(int o){
    t[o].sum=t[o<<1].sum+t[o<<1|1].sum;
    t[o].lmax=max(t[o<<1].sum+t[o<<1|1].lmax,t[o<<1].lmax);
    t[o].rmax=max(t[o<<1|1].sum+t[o<<1].rmax,t[o<<1|1].rmax);
    t[o].max=max(t[o<<1].rmax+t[o<<1|1].lmax,max(t[o<<1].max,t[o<<1|1].max));
}
void build(int o,int l,int r){
    t[o].l=l; t[o].r=r;
    if(l==r){ scanf("%lld",&t[o].sum); t[o].lmax=t[o].rmax=t[o].max=t[o].sum; return; }
    int mid=l+r>>1;
    build(o<<1,l,mid); build(o<<1|1,mid+1,r);
    pushup(o);
}
void updata(int o,int x,int k){
    if(t[o].l==t[o].r&&t[o].l==x){ t[o].sum=t[o].lmax=t[o].rmax=t[o].max=k; return; }
    int mid=t[o].l+t[o].r>>1;
    if(x>mid) updata(o<<1|1,x,k);
    else updata(o<<1,x,k);
    pushup(o);
}
tree query(int o,int l,int r){
    if(t[o].l==l&&t[o].r==r) return t[o];
    int mid=t[o].l+t[o].r>>1;
    if(l>mid) return query(o<<1|1,l,r);
    else if(r<=mid) return query(o<<1,l,r);
    else{
        tree lo,ro,no;
        lo=query(o<<1,l,mid);
        ro=query(o<<1|1,mid+1,r);
        no.sum=lo.sum+ro.sum;
        no.lmax=max(lo.lmax,lo.sum+ro.lmax);
        no.rmax=max(ro.rmax,ro.sum+lo.rmax);
        no.max=max(lo.rmax+ro.lmax,max(lo.max,ro.max));
        return no;
    }
}
signed main(){
    scanf("%lld",&n);
    build(1,1,n);
    scanf("%lld",&m);
    while(m--){
        scanf("%lld %lld %lld",&opt,&l,&r);
        if(opt==0) updata(1,l,r);
        else printf("%lld\n",query(1,l,r).max);
    }
    return 0;
}

转载于:https://www.cnblogs.com/PotremZ/p/SPOJGSS1_GSS3.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值