题意:询问一个区间内的最大连续子段和(GSS1),并且有单点修改的操作(GSS2)。

思路:这个题目在老人家的大白鼠里出现过,不过那个是求两个下标,并且相同取更小值。——传的东西更多,判断也稍微繁琐一些。。。

考虑我们平时如何处理最大连续子段和——O(n)DP,然而显然在一个时刻会修改的序列上无法实现。我们至少需要一个O(nlgn)的算法。考虑到这种连续的和可以对应线段树的一些操作,我们就将它应用到线段树上。

老人家在讲子段和的时候提供了一种分治算法——如果将一段序列分成两端,那么它的最大子段和要么完全出现在左边,要么完全出现在右边,要么横跨中点。那么我们可以将线段树维护这么几个状态——这段序列最大前缀(即一定包括序列头),最大后缀(一定包括序列尾),中间最大值(没有什么限制),整段序列和。

对于每一段序列,如何处理它的最大值呢?

在线段树中左右两个儿子分别代表了左序列与右序列,那么构成这个序列最大子序列和要么是左序列的最大要么是右序列的最大要么值左序列后缀加上右序列的前缀——三个判断分别处理即可。(具体看代码

/*==========================================================================
# Last modified: 2016-02-02 15:50
# Filename: GSS1.cpp
# Description:
==========================================================================*/
#define me AcrossTheSky
#include <cstdio>
#include <cmath>
#include <ctime>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm> #include <set>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#define lowbit(x) (x)&(-x)
#define INF 1000000000
#define FOR(i,a,b) for((i)=(a);(i)<=(b);(i)++)
#define FORP(i,a,b) for(int i=(a);i<=(b);i++)
#define FORM(i,a,b) for(int i=(a);i>=(b);i--)
#define ls(a,b) (((a)+(b)) << 1)
#define rs(a,b) (((a)+(b)) >> 1)
#define maxn 100000
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
/*==================split line==================*/
struct interval{
int sub,sum,suf,pre,v;
}tree[maxn*3];
int L,R,q,n,p;
int a[maxn];
void updata(int node,int l,int r){
if (l==r) {
int x=p;
tree[node].v=x; tree[node].sub=x;
tree[node].pre=x; tree[node].suf=x;
tree[node].sum=x;
return;
}
int mid=rs(l,r),lc=ls(node,0),rc=lc|1;
if (q<=mid) updata(lc,l,mid);
else updata(rc,mid+1,r);
tree[node].sum=tree[lc].sum+tree[rc].sum;
tree[node].pre=max(tree[lc].pre,tree[lc].sum+tree[rc].pre);
tree[node].suf=max(tree[rc].suf,tree[rc].sum+tree[lc].suf); tree[node].sub=max(tree[lc].sub,tree[rc].sub);
tree[node].sub=max(tree[node].sub,tree[lc].suf+tree[rc].pre);
}
void build_tree(int node,int l,int r){
if (l==r) {
int x=a[l];
tree[node].v=x; tree[node].sub=x;
tree[node].pre=x; tree[node].suf=x;
tree[node].sum=x;
return;
}
int mid=rs(l,r),lc=ls(node,0),rc=lc|1;
build_tree(lc,l,mid);build_tree(rc,mid+1,r);
tree[node].sum=tree[lc].sum+tree[rc].sum;
tree[node].pre=max(tree[lc].pre,tree[lc].sum+tree[rc].pre);
tree[node].suf=max(tree[rc].suf,tree[rc].sum+tree[lc].suf); tree[node].sub=max(tree[lc].sub,tree[rc].sub);
tree[node].sub=max(tree[node].sub,tree[lc].suf+tree[rc].pre);
}
void reset(interval &x){
x.sub=-INF; x.v=-INF; x.pre=-INF; x.suf=-INF; x.sum=-INF;
}
interval query(int node,int l,int r){
if (L<=l && r<=R) return tree[node];
int mid=rs(l,r),lc=ls(node,0),rc=lc|1;
interval x,y;
reset(x); reset(y);
x.sum=0; y.sum=0;
if (L<=mid) x=query(lc,l,mid);
if (R>mid) y=query(rc,mid+1,r);
interval ans;
reset(ans);
ans.sub=max(max(x.sub,y.sub),x.suf+y.pre);
ans.suf=max(y.suf,y.sum+x.suf);
ans.pre=max(x.pre,x.sum+y.pre);
ans.sum=x.sum+y.sum;
return ans;
}
int main(){
freopen("a.in","r",stdin);
memset(tree,0,sizeof(tree));
cin >> n;
FOR(q,1,n) scanf("%d",&a[q]);
build_tree(1,1,n);
int m; cin >> m;
FORP(i,1,m){
int t; scanf("%d",&t);
if (t==1){
scanf("%d%d",&L,&R);
printf("%d\n",query(1,1,n).sub);
}
else {
scanf("%d%d",&q,&p);
updata(1,1,n);
}
}
}

GSS系列(1)——GSS1&&GSS3的更多相关文章

  1. spoj gss1 gss3

    传送门 gss1 gss3 spoj gss系列=最大字段和套餐 gss1就是gss3的无单点修改版 有区间查询和单点修改,考虑用线段树维护 我们要维护区间权值和\(s\),区间最大前缀和\(xl\) ...

  2. SPOJ GSS 系列

    来怒做GSS系列了: GSS1:https://www.luogu.org/problemnew/show/SP1043 这题就是维护一个 sum , mx , lmx , rmx,转移时用结构体就好 ...

  3. spoj GSS系列简要题解

    文章目录 GSS1 GSS2 GSS3 GSS4 GSS5 GSS6 GSS7 GSS8 传送门 这个GSSGSSGSS系列全部是跟子段有关的数据结构菜题. 于是来水一篇博客. GSS1 传送门 题意 ...

  4. SPOJ GSS系列

    众所周知的仅次于ynoi的毒瘤数据结构系列.(跟Qtree系列并列?) GSS1: 长度为 $n$ 的序列 $a$,$m$ 个询问,每次询问区间 $[l,r]$ 之间的最大子段和. $1\le n,m ...

  5. SPOJ GSS系列(数据结构维护技巧入门)

    题目链接 GSS $GSS1$ 对于每个询问$l$, $r$,查询$a_{l}$, $a_{l+1}$, $a_{l+2}$, ..., $a_{r}$这个序列的最大字段和. 建立线段树,每个节点维护 ...

  6. SPOJ - GSS1&&GSS3

    GSS1 #include<cstdio> #include<iostream> #define lc k<<1 #define rc k<<1|1 u ...

  7. GSS 系列题解

    GSS GSS1 随便猫树或者线段树,就可以过了 猫树不说,线段树可以维护左边最大,右边最大,区间最大,区间值然后就做出来了. //Isaunoya #pragma GCC optimize(2) # ...

  8. 激!GSS系列

    #include <cstdio> ; ; inline int max(int, int); inline int getint(); inline void putint(int); ...

  9. SPOJ GSS1 && GSS3 (无更新/更新单点,并询问区间最大连续和)

    http://www.spoj.com/problems/GSS1/ 题意:无更新询问区间最大连续和. 做法:线段树每个节点维护sum[rt],maxsum[rt],lsum[rt],rsum[rt] ...

随机推荐

  1. 重构edit 和 new页面

    www.iwangzheng.com 由于edit和new页面的相似部分很多,需要提取出来,现在就是提取的方法 从form 的开始部分选中,shift+v选中对应的行 :Rextract form 然 ...

  2. 2015安徽省赛 F.多重部分和问题

    题目描述 有n种不同大小的数字,每种各个.判断是否可以从这些数字之中选出若干使它们的和恰好为K. 输入 首先是一个正整数T(1<=T<=100) 接下来是T组数据 每组数据第一行是一个正整 ...

  3. Lucas的数论题解

    Lucas的数论 reference 题目在这里> < Pre 数论分块 默认向下取整时. 形如\(\sum\limits_{i=1}^n f\left( \frac{n}{i}\righ ...

  4. 从Trie谈到AC自动机

    ZJOI的SAM让我深受打击,WJZ大神怒D陈老师之T3是SAM裸题orz...我还怎么混?暂且写篇`从Trie谈到AC自动机`骗骗经验. Trie Trie是一种好玩的数据结构.它的每个结点存的是字 ...

  5. XPath 定位----光荣之路

    被测试网页的HMTL代码 <html> <body> <div id="div1"> <input name="div1inpu ...

  6. 如何利用phpize在生产环境中为php添加新的扩展php-bcmath

    在日常的开发当中,随着开发的功能越来越复杂.对运行环境的要求也就随着需求的变化需要不断地更新和变化.一个在线的生产系统不可能一开始就满足了所有的运行依赖,因此动态地添加依赖就显得比较必要了.如果你的应 ...

  7. 【JAVA、C++】LeetCode 020 Valid Parentheses

    Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the inpu ...

  8. Java数据类型和运算符

    一,数据类型分类(2种) 1. 基本数据类型(3种) 数值型: 整数类型(4种): byte(1字节):范围(-128~127): short(2字节):范围(-32768~32767): int(4 ...

  9. [SVN(Ubuntu)] SVN 查看历史详细信息

    转载: http://lee2013.iteye.com/blog/1074457 以下内容,对ubuntu命令行查看代码变化非常有用. SVN 查看历史信息 通过svn命令可以根据时间或修订号去除过 ...

  10. mongoose学习笔记3--简单查询1

    简述 查询就是返回一个集合中的文档的子集 Mongoose 模型提供了 find. findOne. findById 三种方法用于文档查询. 为了方便后面课程的有效学习,我们先添加一些测试数据. T ...