• 最大连续子数列和


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

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

    Sample Output
    7


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

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

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

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

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

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

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

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    using 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
    ",Tree.tree[1].now);
        }
        return 0;
    }
    
  • 相关阅读:
    Java实现 蓝桥杯VIP 算法提高 快速幂
    Java实现 蓝桥杯VIP 算法提高 最长字符序列
    Java实现 蓝桥杯VIP 算法提高 最长字符序列
    Java实现 蓝桥杯VIP 算法提高 最长字符序列
    Java实现 蓝桥杯VIP 算法提高 最长字符序列
    Java实现 蓝桥杯VIP 算法提高 最长字符序列
    linux下配置QT(很全的步骤,从下载开始,配置QMAKESPEC)
    QT 读取文件夹下所有文件(超级简单的方法,不需要QDirIterator)
    Windows平台下的图形化的Ping工具
    Qt中的键盘事件,以及焦点的设置(比较详细)
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/8414568.html
Copyright © 2020-2023  润新知