动态 dp & 矩阵乘法

不二咲千寻太可爱了

矩阵乘法:

这里写成

\[(f[i],a[i-1],0)\begin{bmatrix} a[i] & a[i] & -inf \ \\ -inf & 0 & -inf \ \\ a[i] & a[i] & 0 \\ \end{bmatrix}=(f[i],a[i],0)\]

的形式。

右手边的矩阵第 \(i\)\(j\) 列是第一个矩阵的第 \(i\) 行和第二个矩阵的第 \(j\) 列的各个数相乘的积的和。

而这里的广义矩阵中,乘法加法可以改变成各个满足分配律、结合律等运算律的运算。

在线段树上面维护这样的矩阵乘法就完美了。

比如上面的矩阵

\[\begin{bmatrix} a[i] & a[i] & -inf \ \\ -inf & 0 & -inf \ \\ a[i] & a[i] & 0 \\ \end{bmatrix}\]

其实就是最大子段和的递推式 \(f[i]=max(f[i-1]+a[i],a[i])\) 和递推式 \(ans[i]=max(ans[i-1],f[i-1]+a[i],a[i]).\)

依次推导出上面的式子。

发现只是代入 \(f,ans,a\) 这三个参数并不能完全表示,所以要引入参数 \(0,\) 是个小技巧呢。

对于带修改的最大子段和,只要在线段树上面修改就好了。

程式
#include <bits/stdc++.h>
#define ls (rt << 1)

#define rs (rt << 1 | 1)

#define lson ls, l, mid

#define rson rs, mid + 1, r

#define mid ((l + r) >> 1)

#define int long long


inline bool max(int &x, int y) { return (x < y ? (x = y, true) : false); }
const int N = 1e6 + 10, inf = 1e9 + 6;
struct matrix {
    int m[3][3];
};
matrix w = { { { -inf, -inf, -inf }, { -inf, -inf, -inf }, { -inf, -inf, -inf } } };
int val[N];
inline matrix mul(matrix a, matrix b) {
    matrix c = w;
    for (int k = 0; k < 3; ++k)
        for (int i = 0; i < 3; ++i)
            for (int j = 0; j < 3; ++j) max(c.m[i][j], a.m[i][k] + b.m[k][j]);
    return c;
}

inline matrix ch(int v) {
    matrix q;
    q.m[0][0] = q.m[0][2] = q.m[1][0] = q.m[1][2] = v;
    q.m[0][1] = q.m[2][0] = q.m[2][1] = -inf;
    q.m[1][1] = q.m[2][2] = 0;
    return q;
}

namespace sgt {
	matrix t[N << 2];
	inline void pu(int rt) { return t[rt] = mul(t[ls], t[rs]), void(); }
	void update(int rt, int l, int r, int p, matrix k) {
	    if (l == r) {
	        return t[rt] = k, void();
	    }
	    if (p <= mid)
	        update(lson, p, k);
	    if (p > mid)
	        update(rson, p, k);
	    return pu(rt), void();
	}
	matrix query(int rt, int l, int r, int L, int R) {
	    if (L <= l && r <= R)
	        return t[rt];
	    if (L <= mid && R > mid) {
	        return mul(query(lson, L, R), query(rson, L, R));
	    }
	    if (L <= mid)
	        return query(lson, L, R);
	    if (R > mid)
	        return query(rson, L, R);
	}
	void build(int rt, int l, int r) {
	    if (l == r)
	        return t[rt] = ch(val[l]), void();
	    build(lson), build(rson), pu(rt);
	    return void();
	}
}

int n, m;
signed main() {
    scanf("%lld%lld", &n, &m);
    for (int i = 1; i <= n; ++i) scanf("%lld", val + i), sgt2::update(1, 1, n, i, val[i]);
    sgt::build(1, 1, n);
    while (m--) {
        int k;
        scanf("%lld", &k);
        if (k == 2) {
            int p, s;
            scanf("%lld%lld", &p, &s);
            sgt2::update(1, 1, n, p, s);
            sgt::update(1, 1, n, p, ch(s));
        } else {
            int l, r;
            scanf("%lld%lld", &l, &r);
            if(l>r) std::swap(l,r);
            matrix ans = sgt::query(1, 1, n, l, r);
            printf("%lld\n", std::max(ans.m[1][0],ans.m[1][2]));
        }
    }
    return 0;
}
posted @ 2024-05-03 00:05  ChihiroFujisaki  阅读(75)  评论(0)    收藏  举报