【数据结构 数学 线段树 矩阵乘法 动态dp】SP1716 GSS3 Can you answer these queries III

57 篇文章 0 订阅
53 篇文章 0 订阅

题意

之前

思路

考虑动态规划求最大子段和。
f i f_i fi为以 a i a_i ai结尾的最大子段和, g i g_i gi a i a_i ai前的最大子段和,得出方程:
f i = m a x ( f i − 1 + a i , a i ) 、 g i = m a x ( g i − 1 , f i ) f_i=max(f_{i-1}+a_i,a_i)、g_i=max(g_{i-1},f_i) fi=max(fi1+ai,ai)gi=max(gi1,fi)
将矩阵乘法运算改变,可以将方程改成矩阵乘法:
在这里插入图片描述
对于每个 a i a_i ai都有一个矩阵 G i G_i Gi,计算答案时用 G l G_l Gl乘到 G r G_r Gr,对于修改就直接把矩阵修改即可,线段树维护。
这就原来就是动态 d p dp dp的入门了。。

代码

#include<cstdio>
#include<climits>
#include<cstring>
#include<algorithm>

const int inf = INT_MAX >> 1;//÷2不然加起来会爆炸

struct matrix {
	int a[4][4];
};
struct SegmentTree {
	int l, r;
	matrix dat;
}t[200001];
int n, m;
int a[50001];

matrix operator *(const matrix &a, const matrix &b){
    matrix c;
    for (int i = 1; i <= 3; i++)
    	for (int j = 1; j <= 3; j++)
    		c.a[i][j] = -inf;
	for (int i = 1; i <= 3; i++)
        for (int j = 1; j <= 3; j++)
            for (int k = 1; k <= 3; k++)
                c.a[i][j] = std::max(c.a[i][j], a.a[i][k] + b.a[k][j]);
    return c;
}

void build(int p, int l, int r) {
	t[p].l = l;
	t[p].r = r;
	if (l == r) {
		t[p].dat.a[1][1] = t[p].dat.a[1][3] = t[p].dat.a[2][1] = t[p].dat.a[2][3] = a[l];
		t[p].dat.a[1][2] = t[p].dat.a[3][1] = t[p].dat.a[3][2] = -inf;
		t[p].dat.a[2][2] = t[p].dat.a[3][3] = 0;
		return;
	}
	int mid = l + r >> 1;
	build(p << 1, l, mid);
	build(p << 1 | 1, mid + 1, r);
	t[p].dat = t[p << 1].dat * t[p << 1 | 1].dat;
}

matrix query(int p, int l, int r) {
	if (l <= t[p].l && t[p].r <= r)
		return t[p].dat;
	int mid = t[p].l + t[p].r >> 1; 
	if (l <= mid && r > mid) return query(p << 1, l, r) * query(p << 1 | 1, l, r);
	else if (l <= mid) return query(p << 1, l, r);
	else if (r > mid) return query(p << 1 | 1, l, r);
}

void modify(int p, int pos, int val) {
	if (t[p].l == t[p].r) {
		t[p].dat.a[1][1] = t[p].dat.a[1][3] = t[p].dat.a[2][1] = t[p].dat.a[2][3] = val;
		return;
	}
	int mid = t[p].l + t[p].r >> 1;
	if (pos <= mid) modify(p << 1, pos, val);
	else modify(p << 1 | 1, pos, val);
	t[p].dat = t[p << 1].dat * t[p << 1 | 1].dat;
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	build(1, 1, n);
	scanf("%d", &m);
	for (int op, x, y; m; m--) {
		scanf("%d %d %d", &op, &x, &y);
		if (op) {
			matrix res = query(1, x, y);
			printf("%d\n", std::max(res.a[2][1], res.a[2][3]));
		}
		else modify(1, x, y);
	}
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值