最大连续子数列和

来源:互联网 发布:天下三男奕剑捏脸数据 编辑:程序博客网 时间:2024/05/16 05:10

Description
给定一数列,规定有两种操作
一是修改某个元素
二是求子数列的连续最大和。
数列的元素个数最多10万个,询问操作最多10万次

Sample Input
4 2
1
2
-3
2
1 3 2
2

Sample Output
7

非常经典的最大连续子数列和问题。

考虑下最暴力的做法,枚举开始点和结束点,再统计其中的答案,O(N3)的算法

优化一下,记录前缀和,时间复杂度将为O(N2),还是不够优

考虑下用线段树维护,线段树记录4个值,now,left,right,sumnow记录当前区间的最大连续子串和,left记录当前区间从最左边的点开始的最大连续子串和,right方向与left相反,其余相同,sum记录当前区间的和

每次输出now[1]即可。不过,怎么维护?

sum的维护不用多讲;left的维护,要么是自己左儿子的left,要么是自己左儿子的sum加上右儿子的leftright除了方向与left相反外,其余相同;now的更新,要么是两个儿子的now的最大值,要么就是左儿子的right加上右儿子left

因为是连续子串,所以按上面说的更新,知道了这点,就是傻逼线段树了

#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define inf 0x7f7f7f7fusing namespace std;typedef long long ll;typedef unsigned int ui;typedef unsigned long long ull;inline int read(){    int x=0,f=1;char ch=getchar();    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<1)+(x<<3)+ch-'0';    return x*f;}inline void print(int x){    if (x>=10)     print(x/10);    putchar(x%10+'0');}const int N=1e5;int val[N+10];struct Segment{    #define ls (p<<1)    #define rs (p<<1|1)    struct AC{        int left,right,now,sum;        void init(int x){left=right=now=sum=x;}    }tree[N*4+10];    AC updata(AC x,AC y){//更新,x是左儿子,y是右儿子        AC z; z.init(0);        z.now=max(max(x.now,y.now),x.right+y.left);        z.left=max(x.left,x.sum+y.left);        z.right=max(y.right,y.sum+x.right);        z.sum=x.sum+y.sum;        return z;    }    void build(int p,int l,int r){        if (l==r){            tree[p].init(read());            return;        }        int mid=(l+r)>>1;        build(ls,l,mid),build(rs,mid+1,r);        tree[p]=updata(tree[ls],tree[rs]);    }    void change(int p,int l,int r,int x,int t){        if (l==r){            tree[p].init(t);            return;        }        int mid=(l+r)>>1;        if (x<=mid) change(ls,l,mid,x,t);        if (x>mid)  change(rs,mid+1,r,x,t);        tree[p]=updata(tree[ls],tree[rs]);    }}Tree;int main(){    int n=read(),m=read();    Tree.build(1,1,n);    for (int i=1;i<=m;i++){        int t=read();        if (t==1){            int x=read(),y=read();            Tree.change(1,1,n,x,y);        }        else    printf("%d\n",Tree.tree[1].now);    }    return 0;}