动态动态规划(DDP)

1.Problem - E - Codeforces

       一.题目大意

         给你一个无向图,第i和i+1条边的权值是w[i],问你每个点不在自己原本的点的代价是多少,会有q组询问,表示修改第i条边的权值。
        

        二.解题思路

                可以观察到,完成这个操作需要每条边经过两次,那么我们在不考虑修改的情况下进行dp[i]表示考虑前i条边,最后一条边经过i的最小代价。此时状态转移方程可以很显然的观察出来就是dp[i] = min(dp[i - 1],dp[i - 2]) + a[i]。

                考虑到修改,我们利用线段树维护dp的过程,考虑一个递推式子,我们可以构造出一个矩阵,右乘一个​​​​​​​等于,当我们把乘法定义为+法,求和定义为取min,那么这个矩阵就符合转移方程,因此只需要构造n个A矩阵,就可以把答案递推出来,此时用线段树维护矩阵修改就行。

        三.代码实现

                 

#include "bits/stdc++.h"
using namespace std;
using ll = long long;

const int N = 2e5 + 10;
const ll inf = 0x3f3f3f3f3f3f3f3f;
struct Mat {
	ll dp[2][2];
	Mat operator *(const Mat &T) const {
		Mat res;
		for(int i = 0;i < 2;i ++) {
			for(int j = 0;j < 2;j ++) {
				res.dp[i][j] = inf;
				for(int k = 0;k < 2;k ++) {
					res.dp[i][j] = min(res.dp[i][j],dp[i][k] + T.dp[k][j]);
				}
			}
		}
		return res;
	}
};

Mat bas[N],val[N << 2];
void push_up(int u)
{
	val[u] = val[u << 1] * val[u << 1 | 1];
}

void build(int u,int l,int r)
{	
	if(l == r) {
		val[u] = bas[l];
		return;
	}
	int mid = (l + r) >> 1;
	build(u << 1,l,mid);
	build(u << 1 | 1,mid + 1,r);
	push_up(u);
}

void modify(int u,int l,int r,int p)
{
	if(l == r) {
		val[u] = bas[p];
		return;
	}
	int mid = (l + r) >> 1;
	if(p <= mid) modify(u << 1,l,mid,p);
	else modify(u << 1 | 1,mid + 1,r,p);
	push_up(u);
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int n;
	cin >> n;
	n --;
	for(int i = 1,x;i <= n;i ++) {
		cin >> x;
		bas[i].dp[0][0] = bas[i].dp[0][1] = x;
		bas[i].dp[1][1] = inf;
	}
	build(1,1,n);
	int q;
	cin >> q;
	while(q --) {
		int p,v;
		cin >> p >> v;
		bas[p].dp[0][0] = bas[p].dp[0][1] = v;
		bas[p].dp[1][1] = inf;
		modify(1,1,n,p);
		cout << val[1].dp[0][1] * 2 << '\n';
	}
	return 0;
}

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值