• SP1716 GSS3


    GSS3

    Description

    动态维护最大子段和,支持单点修改。

    Solution

    (f[i]) 表示以 (i) 为结尾的最大子段和, (g[i]) 表示 (1 sim i) 的最大子段和,那么

    [f[i] = max(f[i - 1] + a[i], a[i]) ]

    [g[i] = max(g[i - 1], f[i]) ]

    发现只跟前一项有关。我们希望使用矩阵乘法的思路,但是矩阵乘法通常只能适用于递推问题。因此我们引入广义矩阵乘法。

    矩阵乘法问题可分治的原因在于矩阵乘法满足结合律,而满足结合律的根本原因是乘法对加法满足分配率,即

    [acdot (b+c) = acdot c + bcdot c ]

    那么在这里,很容易发现,加法运算对(Min/Max)运算也是满足分配率的,即

    [a + min(b,c) = min(a+c,b+c) ]

    [a + max(b,c) = max(a+c,b+c) ]

    所谓广义矩阵乘法,就是将矩阵乘法中的加法运算换成(Min/Max)运算,乘法运算换成加法运算,那么这样的矩阵乘法仍然满足结合律。

    考虑到 (g[i])(f[i]) 转移过来的那一项可以直接拆开,很容易得到转移方程

    [egin{bmatrix} f_{i} \ g_{i} \ 0 end{bmatrix} = egin{bmatrix} a_{i} & -infty & a_{i} \ a_{i} & 0 & a_{i}\ -infty & -infty & 0 \ end{bmatrix} cdot egin{bmatrix} f_{i-1} \ g_{i-1} \ {0} end{bmatrix} ]

    可以将其记为

    [F_i = A_i cdot F_{i-1} ]

    于是我们用线段树暴力维护所有(A_i)的乘积即可。复杂度(O(27n log{n}))

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    struct Matrix {
    	int n,m,a[5][5];
    	Matrix() {
    		n=m=0;
    		for(int i=0;i<4;i++) for(int j=0;j<4;j++) a[i][j]=0;
    	}
    	Matrix operator * (const Matrix &y) {
    		Matrix r;
    		if(m!=y.n) return r;
    		r.n = n; r.m = y.m;
    		for(int i=1;i<=n;i++) {
    			for(int j=1;j<=y.m;j++) {
    				for(int k=1;k<=m;k++) {
    					if(k==1) r.a[i][j]=a[i][k]+y.a[k][j];
    					else r.a[i][j]=max(r.a[i][j],a[i][k]+y.a[k][j]);
    				}
    			}
    		}
    		return r;
    	}
    }; 
    Matrix make(int x) {
    	Matrix r;
    	r.m=r.n=3;
    	r.a[1][1]=r.a[1][3]=r.a[2][1]=r.a[2][3]=x;
    	r.a[2][2]=r.a[3][3]=0;
    	r.a[1][2]=r.a[3][1]=r.a[3][2]=-1e+9;
    	return r;
    }
    
    const int N = 1000005;
    
    Matrix val[N],zero;
    int n,q,src[N],t1,t2,t3;
    
    void pushup(int p) {
    	val[p] = val[p*2]*val[p*2+1];
    }
    void build(int p,int l,int r) {
    	if(l==r) {
    		val[p]=make(src[l]);
    	}
    	else {
    		build(p*2,l,(l+r)/2);
    		build(p*2+1,(l+r)/2+1,r);
    		pushup(p); 
    	}
    }
    void modify(int p,int l,int r,int pos,int key) {
    	if(l==r) {
    		val[p]=make(key);
    	}
    	else {
    		if(pos<=(l+r)/2) modify(p*2,l,(l+r)/2,pos,key);
    		else modify(p*2+1,(l+r)/2+1,r,pos,key);
    		pushup(p); 
    	}
    }
    Matrix query(int p,int l,int r,int ql,int qr) {
    	Matrix R=make(-1e+9);
    	if(l>qr||r<ql) return R;
    	if(l>=ql&&r<=qr) return val[p];
    	return query(p*2,l,(l+r)/2,ql,qr)*query(p*2+1,(l+r)/2+1,r,ql,qr);
    }
    
    signed main() {
    	ios::sync_with_stdio(false);
    	cin>>n;
    	for(int i=1;i<=n;i++) cin>>src[i];
    	cin>>q;
    	zero.n=3; zero.m=1;
    	zero.a[1][1]=zero.a[2][1]=-1e+9;
    	build(1,1,n);
    	for(int i=1;i<=q;i++) {
    		cin>>t1>>t2>>t3;
    		if(t1==0) {
    			modify(1,1,n,t2,t3);
    		}
    		else {
    			Matrix r=query(1,1,n,t2,t3)*zero;
    			cout<<r.a[2][1]<<endl;
    		}
    	}
    }
    

    当然似乎这个问题用线段树暴力又短又快

    #include <bits/stdc++.h>
    using namespace std;
    
    int src[1000005],a[1000005],al[1000005],ar[1000005],s[1000005],n,m,t1,t2,t3,t4;
    
    struct Result {
    	int a,al,ar,s;
    };
    
    void build(int p,int l,int r) {
    	if(l==r) a[p]=al[p]=ar[p]=s[p]=src[l];
    	else {
    		build(p<<1,l,(l+r)/2),
    		build(p<<1|1,(l+r)/2+1,r);
    		a[p]=max(max(a[p<<1],a[p<<1|1]),max(max(ar[p<<1],al[p<<1|1]),ar[p<<1]+al[p<<1|1]));
    		al[p]=max(al[p<<1],s[p<<1]+max(0,al[p<<1|1]));
    		ar[p]=max(ar[p<<1|1],max(0,ar[p<<1])+s[p<<1|1]);
    		s[p]=s[p*2]+s[p*2+1];
    	}
    }
    
    void modify(int p,int l,int r,int pos,int key) {
    	if(l==r) a[p]=al[p]=ar[p]=s[p]=key;
    	else {
    		if(pos<=(l+r)/2) modify(p<<1,l,(l+r)/2,pos,key);
    		else modify(p<<1|1,(l+r)/2+1,r,pos,key);
    		a[p]=max(max(a[p<<1],a[p<<1|1]),max(max(ar[p<<1],al[p<<1|1]),ar[p<<1]+al[p<<1|1]));
    		al[p]=max(al[p<<1],s[p<<1]+max(0,al[p<<1|1]));
    		ar[p]=max(ar[p<<1|1],max(0,ar[p<<1])+s[p<<1|1]);
    		s[p]=s[p*2]+s[p*2+1];
    	}
    }
    
    Result query(int p,int l,int r,int ql,int qr) {
    	Result res;
    	res.a=-1e+8;
    	res.al=-1e+8;
    	res.ar=-1e+8;
    	res.s=-1e+8;
    	if(l>qr||r<ql) return res;
    	if(l>=ql&&r<=qr) {
    		res.a=a[p];
    		res.al=al[p];
    		res.ar=ar[p];
    		res.s=s[p];
    		return res;
    	}
    	else {
    		Result cl,cr;
    		cl=query(p<<1,l,(l+r)/2,ql,qr);
    		cr=query(p<<1|1,(l+r)/2+1,r,ql,qr);
    		res.a=max(max(cl.a,cr.a),max(max(cl.ar,cr.al),cl.ar+cr.al));
    		res.al=max(cl.al,cl.s+max(0,cr.al));
    		res.ar=max(cr.ar,max(0,cl.ar)+cr.s);
    		res.s=cl.s+cr.s;
    		return res;
    	}
    }
    
    int main(){
    	ios::sync_with_stdio(false);
    	cin>>n;
    	for(int i=1;i<=n;i++) cin>>src[i];
    	build(1,1,n);
    	cin>>m;
    	for(int i=1;i<=m;i++) {
    		cin>>t3>>t1>>t2;
    		if(t3) {
    			Result res=query(1,1,n,t1,t2);
    			cout<<res.a<<endl;
    		}
    		else {
    			modify(1,1,n,t1,t2);
    		}
    	}
    }
    
  • 相关阅读:
    css flex布局应用
    Java 中 List、HashTable、HashMap、TreeMap
    Java 面向对象的三大特征
    Java-冒泡排序算法
    单例模式- 实现方式
    Mac
    Appium DesiredCapabilities 参数设置
    Mac- appium 环境配置
    PHP安装+使用
    mac 安装protobuf,并编译
  • 原文地址:https://www.cnblogs.com/mollnn/p/11656378.html
Copyright © 2020-2023  润新知