• SP1716 GSS3


    题面

    题解

    相信大家写过的传统做法像这样:(这段代码蒯自Karry5307的题解

    struct SegmentTree{
        ll l,r,prefix,suffix,sum,maxn;  
    };
    
    //...
    
    inline void update(ll node)
    {
        ll res;
        tree[node].sum=tree[node<<1].sum+tree[(node<<1)|1].sum;
        tree[node].maxn=max(tree[node<<1].maxn,tree[(node<<1)|1].maxn);
        res=tree[node<<1].suffix+tree[(node<<1)|1].prefix;
        tree[node].maxn=max(tree[node].maxn,res);
        res=tree[node<<1].sum+tree[(node<<1)|1].prefix;
        tree[node].prefix=max(tree[node<<1].prefix,res);
        res=tree[node<<1].suffix+tree[(node<<1)|1].sum;
        tree[node].suffix=max(tree[(node<<1)|1].suffix,res);
    }
    
    //...
    

    有没有觉得这种做法有些麻烦

    这里将一种硬核做法:动态dp

    这个部分参考了GKxx 的博客

    引入广义矩阵乘法:

    [mathrm{C} = mathrm{A} * mathrm{B} Leftrightarrow mathrm{C}_{i,j} = max_kleft{mathrm{A}_{i,k} + mathrm{B}_{k,j} ight} ]

    这样的话,我们首先写出动态规划的柿子:

    (f_i)表示以(i)结尾的最大子段和,(g_i)表示([1,i])的最大子段和

    于是

    [egin{aligned} f_i &= max(f_{i-1} + a_i, a_i) \ g_i &= max(g_{i-1}, f_i) end{aligned} ]

    欢乐地写出矩乘的柿子:

    [egin{bmatrix}f_{i-1} & g_{i-1} & 0end{bmatrix} imesegin{bmatrix}a_i & a_i & -infty\-infty & 0 & -infty\a_i & a_i & 0end{bmatrix}=egin{bmatrix}f_i & g_i & 0end{bmatrix} ]

    妙哉

    因为矩阵乘法具有结合律,于是可以用线段树维护

    当然资瓷单点修改和查询区间最大子段和了

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define RG register
    #define file(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout);
    #define clear(x, y) memset(x, y, sizeof(x));
    
    inline int read()
    {
    	int data = 0, w = 1;
    	char ch = getchar();
    	while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    	if(ch == '-') w = -1, ch = getchar();
    	while(ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();
    	return data * w;
    }
    
    const int maxn(50010), INF(0x3f3f3f3f);
    template<typename T> inline void chkmax(T &a, const T &b)
    	{ return (void) (a < b ? a = b : 0); }
    struct Matrix
    {
    	int a[3][3];
    	inline int *operator [] (const int &x) { return a[x]; }
    	inline const int *operator [] (const int &x) const { return a[x]; }
    } mat[maxn << 2]; int n, Q, a[maxn];
    
    inline Matrix operator * (const Matrix &a, const Matrix &b)
    {
    	Matrix c; for(int i = 0; i < 3; i++) c[i][0] = c[i][1] = c[i][2] = -INF;
    	for(int i = 0; i < 3; i++)
    		for(int j = 0; j < 3; j++)
    			for(int k = 0; k < 3; k++)
    				chkmax(c[i][k], a[i][j] + b[j][k]);
    	return c;
    }
    
    void build(int root = 1, int l = 1, int r = n)
    {
    	if(l == r)
    	{
    		Matrix &o = mat[root]; o[0][1] = o[2][0] = o[2][1] = -INF;
    		o[0][0] = o[0][2] = o[1][0] = o[1][2] = a[l];
    		o[1][1] = o[2][2] = 0; return;
    	}
    	int mid = (l + r) >> 1, lson = root << 1, rson = lson | 1;
    	build(lson, l, mid), build(rson, mid + 1, r);
    	mat[root] = mat[lson] * mat[rson];
    }
    
    void update(int id, int v, int root = 1, int l = 1, int r = n)
    {
    	if(l == r) return (void)
    		(mat[root][0][0] = mat[root][0][2]
    		 = mat[root][1][0] = mat[root][1][2] = v);
    	int mid = (l + r) >> 1, lson = root << 1, rson = lson | 1;
    	if(id <= mid) update(id, v, lson, l, mid);
    	else update(id, v, rson, mid + 1, r);
    	mat[root] = mat[lson] * mat[rson];
    }
    
    Matrix query(int ql, int qr, int root = 1, int l = 1, int r = n)
    {
    	if(ql <= l && r <= qr) return mat[root];
    	int mid = (l + r) >> 1, lson = root << 1, rson = lson | 1;
    	if(qr <= mid) return query(ql, qr, lson, l, mid);
    	if(ql >  mid) return query(ql, qr, rson, mid + 1, r);
    	return query(ql, qr, lson, l, mid) * query(ql, qr, rson, mid + 1, r);
    }
    
    int main()
    {
    	n = read();
    	for(RG int i = 1; i <= n; i++) a[i] = read();
    	build(); Q = read();
    	while(Q--)
    	{
    		int opt = read(), x = read(), y = read();
    		if(opt)
    		{
    			Matrix ans = query(x, y);
    			printf("%d
    ", std::max(ans[1][0], ans[1][2]));
    		}
    		else a[x] = y, update(x, y);
    	}
    	return 0;
    }
    
  • 相关阅读:
    要如何用[ZT]sendmessage來切換PageControl1 的TabSheet2呢
    Delphi 常用API 函数
    [ZT]如何得到其他程序的Richedit中的RTF数据
    转帖一篇关于DELPHI调试的文章AQTime
    讀取股票資料檔與指標計算方法之封裝
    GC的三代回收机制
    SQL语句的解析过程
    .Net 垃圾回收机制整理
    美国人吃了交通罚单怎么办?
    Ihttphandler,Ihttpmodule
  • 原文地址:https://www.cnblogs.com/cj-xxz/p/10350821.html
Copyright © 2020-2023  润新知