zoukankan      html  css  js  c++  java
  • 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);
    		}
    	}
    }
    
  • 相关阅读:
    HDU 5744
    HDU 5815
    POJ 1269
    HDU 5742
    HDU 4609
    fzu 1150 Farmer Bill's Problem
    fzu 1002 HangOver
    fzu 1001 Duplicate Pair
    fzu 1150 Farmer Bill's Problem
    fzu 1182 Argus 优先队列
  • 原文地址:https://www.cnblogs.com/mollnn/p/11656378.html
Copyright © 2011-2022 走看看