动态DP,ddp
动态DP?动态动态规划?
个人理解:动态DP,就是普通DP加修改操作,然后就变成了个毒瘤题。
直接就着例题写吧。
例题
P4719 【模板】"动态 DP"&动态树分治
求树上最大独立集。要求支持修改点权。n<=1e5.
算法原理
首先不带修的最大独立集是一个NOIP题:
\(f[cur][0/1]\) 表示 \(cur\) 选/不选 其子树内(含 \(cur\))的被选点权值和。
\]
\]
既然要求支持修改,我们可以拿出对付树的利器:树链剖分。将树剖分成重链和轻边。然后 \(f[cur][0/1]\) 含义不变,另设 \(g[cur][0/1]\) 表示不考虑重儿子的 \(f\)。那么有:
\]
\]
为了描述方便,规定 \(i + 1\) 为在重链上与 \(i\) 相邻的比 \(i\) 深的那个点。则:
\]
\]
然后我们发现这样老是[0][1]不方便,直接用 \(2×1\) 的矩阵来表示 \(f, g\),这样的话,我们就发现 \(f\) 矩阵可以由与 \(g\) 有关的矩阵递推:
g_{i,0} & g_{i, 0}\\
g_{i, 1} &
-\infty\end{bmatrix} × \begin{bmatrix}
f_{i+1, 0} \\
f_{i+1, 1}
\end{bmatrix}=\begin{bmatrix}
f_{i,0} \\
f_{i,1}
\end{bmatrix}\]
这样,我们就只用维护每个点的 \(g\) 矩阵,用到 \(f\) 的时候直接拿 \(g\) 矩阵乘一下即可。这个 \(g\) 矩阵是重链上的一堆矩阵,因此我们可以拿线段树维护。
现在考虑修改带来的影响
如果我们修改了某一个点的权值,那么这个点的 \(g\) 矩阵将会改变,不过重链上的其它 \(g\) 矩阵不会改变。但是,重量顶端的父亲的 \(g\) 矩阵会因为重链上的 \(f\) 的改变而改变,因此我们需要修改重链父亲的 \(g\) 矩阵,以及重链父亲所在重链的顶端的父亲的 \(g\) 矩阵...
流程大概是:修改 \(cur\) 的 \(g\) 矩阵,计算 \(top\) 的 \(f\),(如果 \(cur\) 尚不为树根),cur = fa[top[cur]]
,重复。
代码实现
具体实现的时候,我们自然可以严格按照流程的做法来。不过,相比树剖疯狂跳 \(fa[top]\),LCT的 \(Access\) 函数也可以较为轻松地实现这种操作,并且LCT可以将信息直接维护到点上,避开线段树无比笨拙的修改查询操作,砍掉一个 \(log\),而且还不用 \(makeroot\),因此不用 \(pushr,pushdown\),是为数不多的LCT比树剖好写的题。所以,这题用LCT维护原图子树信息是个不错的选择。
还有一些简化代码的小 trick:
一开始可以让所有边都为虚边,直接一遍DFS计算出所有 \(g\) 矩阵。
我们保持1为根节点不变;所有矩阵都可以开成 2×2 的矩阵。这是因为我们矩阵初始化全为 -inf,如果真的要拿一个 2×2 的矩阵和 2×1 的矩阵乘,由于 2×1 矩阵的第二列全为 -inf,最终结果的第二列也将是 -inf,并不会影响答案。
最终统计答案的时候,可以直接 \(splay(1)\) 然后就拿 1 节点的 \(mul\) 计算答案。本来应该是 1 所在的实链的底端的那个 \(f\) 矩阵乘其它的 \(g\) 矩阵,但是我们发现底端 \(g\) 矩阵的第一列恰好是 \(f\) 矩阵的第一列,因此乘出来的第一列就恰好是答案。
关键代码
略微感受到shadowice大佬考场调bug的感觉了,我还是刚学完ddp,理清思路再写,还写出了六七个bug。
int h[N];
matrix val[N], mul[N];
int son[N][2], fa[N];
inline void pushup(int cur) {
mul[cur] = val[cur];
int ls = son[cur][0], rs = son[cur][1];
if (ls) mul[cur] = mul[ls] * mul[cur];
if (rs) mul[cur] = mul[cur] * mul[rs];
}
inline void Access(int cur) {
for (register int p = cur, lst = 0; p; lst = p, p = fa[p]) {
splay(p);//Attention!
if (lst) {
val[p].h[0][0] -= max(mul[lst].h[0][0], mul[lst].h[1][0]);//Attention!!! : mul
val[p].h[1][0] -= mul[lst].h[0][0];//Attention!!! : mul
}
int rs = son[p][1];
if (rs) {
val[p].h[0][0] += max(mul[rs].h[0][0], mul[rs].h[1][0]);//Attention!!!
val[p].h[1][0] += mul[rs].h[0][0];//Attention!!!
}
val[p].h[0][1] = val[p].h[0][0];
son[p][1] = lst;
pushup(p);
}
}
int g[N][2];
void dfs(int cur, int faa) {
g[cur][1] = h[cur]; fa[cur] = faa;
for (register int i = head[cur]; i; i = e[i].nxt) {
int to = e[i].to; if (to == faa) continue;
dfs(to, cur);
g[cur][0] += max(g[to][0], g[to][1]);
g[cur][1] += g[to][0];
}
val[cur].h[0][0] = val[cur].h[0][1] = g[cur][0];
val[cur].h[1][0] = g[cur][1];//Attention!
mul[cur] = val[cur];
}
inline void modify(int cur, int v) {
Access(cur), splay(cur);
// val[cur].h[0][0] += v - h[cur];
// val[cur].h[0][1] = val[cur].h[0][0];
val[cur].h[1][0] += v - h[cur];//Attention!!!
h[cur] = v;//Attention!
pushup(cur);
}
int main() {
dfs(1, 0);
while (m--) {
modify(x, v);
splay(1);
ans = max(mul[1].h[0][0], mul[1].h[1][0]);
}
}
(双倍经验:P5024 保卫王国,只需要多想一点点)
动态DP,ddp的更多相关文章
- 洛谷P4719 【模板】动态dp(ddp LCT)
题意 题目链接 Sol 动态dp板子题.有些细节还没搞懂,待我研究明白后再补题解... #include<bits/stdc++.h> #define LL long long using ...
- 洛谷4719 【模板】动态dp 学习笔记(ddp 动态dp)
qwq大概是混乱的一个题. 首先,还是从一个比较基础的想法开始想起. 如果每次暴力修改的话,那么每次就可以暴力树形dp 令\(dp[x][0/1]\)表示\(x\)的子树中,是否选择\(x\)这个点的 ...
- 「校内训练 2019-04-23」越野赛车问题 动态dp+树的直径
题目传送门 http://192.168.21.187/problem/1236 http://47.100.137.146/problem/1236 题解 题目中要求的显然是那个状态下的直径嘛. 所 ...
- 【学习笔记】动态 dp 入门简易教程
序列 dp 引入:最大子段和 给定一个数列 \(a_1, a_2, \cdots, a_n\)(可能为负),求 \(\max\limits_{1\le l\le r\le n}\left\{\sum_ ...
- Note -「动态 DP」学习笔记
目录 「CF 750E」New Year and Old Subsequence 「洛谷 P4719」「模板」"动态 DP" & 动态树分治 「洛谷 P6021」洪水 「S ...
- 动态DP之全局平衡二叉树
目录 前置知识 全局平衡二叉树 大致介绍 建图过程 修改过程 询问过程 时间复杂度的证明 板题 前置知识 在学习如何使用全局平衡二叉树之前,你首先要知道如何使用树链剖分解决动态DP问题.这里仅做一个简 ...
- Luogu P4643 【模板】动态dp
题目链接 Luogu P4643 题解 猫锟在WC2018讲的黑科技--动态DP,就是一个画风正常的DP问题再加上一个动态修改操作,就像这道题一样.(这道题也是PPT中的例题) 动态DP的一个套路是把 ...
- 动态dp学习笔记
我们经常会遇到一些问题,是一些dp的模型,但是加上了什么待修改强制在线之类的,十分毒瘤,如果能有一个模式化的东西解决这类问题就会非常好. 给定一棵n个点的树,点带点权. 有m次操作,每次操作给定x,y ...
- 洛谷P4719 动态dp
动态DP其实挺简单一个东西. 把DP值的定义改成去掉重儿子之后的DP值. 重链上的答案就用线段树/lct维护,维护子段/矩阵都可以.其实本质上差不多... 修改的时候在log个线段树上修改.轻儿子所在 ...
随机推荐
- -手写Spring注解版本&事务传播行为
视频参考C:\Users\Administrator\Desktop\蚂蚁3期\[www.zxit8.com] 0018-(每特教育&每特学院&蚂蚁课堂)-3期-源码分析-手写Spri ...
- Spring 面试详解
SpringSpring就像是整个项目中装配bean的大工厂,在配置文件中可以指定使用特定的参数去调用实体类的构造方法来实例化对象.Spring的核心思想是IoC(控制反转),即不再需要程序员去显式地 ...
- 几个超级实用但很少人知道的 VS 技巧
大家好,今天分享几个我知道的实用 VS 技巧,而这些技巧我发现很多人都不知道.因为我经常在工作中遇到:我在同事电脑上解决问题,或在会议上演示代码示例时,使用了一些 VS "骚"操作 ...
- 在树莓派上读取DHT11温湿度传感器-python代码实现及常见问题(全面简单易懂)
最近由于自己的课题需要,想要用在树莓派上使用DHT11温湿度传感器来读取空气中温湿度,遇到了几个问题,解决之后也对之前的知识进行了回顾,总结,特整理如下,希望能给也在学习树莓派的小伙伴们带来一些帮助. ...
- Python3-datetime模块-日期与时间
官方文档 http://python.usyiyi.cn/translate/python_352/library/datetime.html 代码示例 from datetime import da ...
- js语法基础入门(1)
1.基础入门 1.1.hello world 1.1.1.JavaScript是什么? JavaScript是一门跨平台.面向对象的轻量级脚本语言,在web开发中被广泛应用 1.1.2.JavaScr ...
- Vue.js 组件复用和扩展之道
软件编程有一个重要的原则是 D.R.Y(Don't Repeat Yourself),讲的是尽量复用代码和逻辑,减少重复.组件扩展可以避免重复代码,更易于快速开发和维护.那么,扩展 Vue 组件的最佳 ...
- 每天一个Linux命令(mkdir)
每天一个Linux命令(mkdir) mkdir: /bin/mkdir,创建目录( make directories)语法:mkdir [选项]... 不存在的目录...目录:默认时必须该目录不存在 ...
- pl/sql案例
项目生命周期: 瀑布模型 拿到一个项目后,首先:分析需要用到的SQL语句: 其次:分析需要定义的变量初始值是多少,怎么得到最终值: 案例一: 统计每年入职的员工数量以及总数量: SQL语句:selec ...
- Lost connection to MYSQL server at 'reading for initial communication packet'
这个异常,是我在对外开放了本地数据库端口后,测试能否连接上数据库时候出现的问题: 解决步骤: 1.services.msc打开服务窗口,重启mysql,进行重试,还不行: 2.对数据库进行操作 USE ...