Luogu P4643 【模板】动态dp(矩阵乘法,线段树,树链剖分)
题面
给定一棵 \(n\) 个点的树,点带点权。
有 \(m\) 次操作,每次操作给定 \(x,y\) ,表示修改点 \(x\) 的权值为 \(y\) 。
你需要在每次操作之后求出这棵树的最大权独立集的权值大小。
题解
如题所示 , 是个模板题 ...
首先考虑静态 \(dp\) , 令 \(dp_{u,0/1}\) 为 \(u\) 不存在 / 存在 于最大权独立集的权值大小 .
然后转移很显然 , 一个点存在于独立集中时 , 儿子全都不能选 . 不存在时 , 儿子可选可不选 .
令 \(v\) 为 \(u\) 的儿子 , 那么转移就有 :
\]
这个如果每次修改直接做是 \(O(n^2)\) 的 , 不能满足要求 .
然而此题是随机数据 . 每次修改单点权值 , 只需要修改这个点到根的 \(dp\) 值就行了 , 期望复杂度 \(O(q \log n + n)\) .
然后跑的飞快 , 怒拿 Luogu rank2.... 但这种随便一条链 , 或者扫帚就挂了 ..
下面就要引入正解了 .
也就是对于这种只有加法和取 \(\max\) 操作的 \(dp\) 我们可以考虑构造矩阵 .
也就是普通矩阵乘法进行改变 , 把 \(\times\) 变成 \(+\) , \(+\) 变成 \(max\) .
也就是 \(\displaystyle C_{i,j} = \sum_{k} A_{i,k} \times B_{k,j}\) 变成 \(\displaystyle C_{i,j} = \max_{k} \{A_{i,k}+B_{k,j}\}\) 就行了.
不难发现这个仍然满足结合律 . (可以用展开来证明 , 或者类似于 \(Floyd\) 的方法理解)
首先树链剖分 , 考虑链上如何修改和询问 . 不难构造矩阵 .
\]
然后我们考虑用线段树维护前面那个矩阵 , 然后每次 \(O(\log n)\) 修改和询问就行了 .
但扩展到树上的时候有些麻烦 , 因为对于一个点可能存在多个儿子 .
但此时它最多只会有一个重儿子 , 我们考虑记下他所有的轻儿子对这个点贡献后的矩阵就行了.
也就是说 令 \(g_{u,0/1}\) 为之前 \(dp_{u, 0/1}\) 去掉重儿子得到的答案 , 那么此时的转移矩阵就变成了 .
\]
请自己展开验证...
然后每次修改的时候 , 只需要在它重链底端的矩阵上进行修改就行了 . (第一个点直接改本身)
修改的话 , 就是得到原来的一个版本和新的一个版本 , 然后对于这个点减去两个版本的差值就行了 .
注意这个版本是意味着这整条重链的版本 , 因为我们要求的是链顶端所有子树最后贡献出来的 \(dp\) 值.
询问的话直接询问 \(1\) 所在重链的答案 . 然后取它选与不选的 \(\max\) 就行了.
注意线段树中的询问 , 最好别写单位矩阵分别乘上左右两边的写法 , 常数会陡增 !!
但还是介绍一下单位矩阵 ... (自己推得qwq) 对角线全都是 \(0\) , 其他位置全是 \(-\infty\) .
也就是 $$\displaystyle \begin{bmatrix} 0 & -\infty & \cdots & -\infty \ -\infty & 0 & \cdots & -\infty \ \vdots & \cdots & \ddots & \vdots \-\infty & -\infty & \cdots & -\infty \ -\infty & -\infty & \cdots & 0\end{bmatrix}$$
最后时间复杂度就是 \(O(n \log^2 n)\) 的... 有点恐怖 , 但跑的还是算快的 . 矩阵乘法那里有 \(8\) 的常数有点伤 .
代码
#include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
using namespace std;
bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}
inline int read() {
int x = 0, fh = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar() ) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar() ) x = (x<<1) + (x<<3) + (ch ^ '0');
return x * fh;
}
void File() {
#ifdef zjp_shadow
freopen ("P4643.in", "r", stdin);
freopen ("P4643.out", "w", stdout);
#endif
}
const int N = 1e5 + 1e3, Lim = 2, inf = 0x7f7f7f7f;
struct Matrix {
int a[Lim + 1][Lim + 1];
Matrix () { Set(a, 0); }
void Unit() { For (i, 1, Lim) For (j, 1, Lim) a[i][j] = (i == j) ? 0 : -inf; }
} ;
inline Matrix operator * (Matrix a, Matrix b) {
Matrix res;
For (i, 1, Lim) For (j, 1, Lim) For (k, 1, Lim) chkmax(res.a[i][j], a.a[i][k] + b.a[k][j]);
return res;
}
void Out(Matrix a) { For (i, 1, Lim) For (j, 1, Lim) printf ("%d%c", a.a[i][j], j == jend ? '\n' : ' '); putchar ('\n'); }
vector<int> G[N];
int sz[N], son[N], fa[N];
void Dfs_Init(int u, int from = 0) {
sz[u] = 1; fa[u] = from;
for (int v : G[u]) if (v ^ from) {
Dfs_Init(v, u), sz[u] += sz[v];
if (sz[v] > sz[son[u]]) son[u] = v;
}
}
int dfn[N], id[N], top[N], back[N];
void Dfs_Part(int u) {
static int clk = 0;
id[dfn[u] = ++ clk] = u;
top[u] = son[fa[u]] == u ? top[fa[u]] : u;
back[top[u]] = u; if (son[u]) Dfs_Part(son[u]);
for (int v : G[u]) if ((v ^ fa[u]) && (v ^ son[u])) Dfs_Part(v);
}
int dp[N][2], val[N];
void Dp_Pre(int u) {
int summax = 0, sum0 = val[u];
for (int v : G[u]) if (v ^ fa[u])
Dp_Pre(v), sum0 += dp[v][0], summax += max(dp[v][0], dp[v][1]);
dp[u][0] = summax, dp[u][1] = sum0;
}
Matrix sub[N];
#define lson o << 1, l, mid
#define rson o << 1 | 1, mid + 1, r
struct Segment_Tree {
Matrix Adv[N << 2];
inline void push_up(int o) { Adv[o] = Adv[o << 1] * Adv[o << 1 | 1]; }
void Build(int o, int l, int r) {
if (l == r) {
int u = id[l], summax = 0, sum0 = val[u];
for (int v : G[u]) if ((v ^ fa[u]) && (v ^ son[u]))
summax += max(dp[v][0], dp[v][1]), sum0 += dp[v][0];
Adv[o].a[1][1] = Adv[o].a[1][2] = summax; Adv[o].a[2][1] = sum0;
sub[u] = Adv[o]; return ;
}
int mid = (l + r) >> 1; Build(lson); Build(rson); push_up(o);
}
void Update(int o, int l, int r, int up) {
if (l == r) { Adv[o] = sub[id[l]]; return ; }
int mid = (l + r) >> 1;
if (up <= mid) Update(lson, up); else Update(rson, up); push_up(o);
}
Matrix Query(int o, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return Adv[o];
int mid = (l + r) >> 1;
/*
Matrix tmp; tmp.Unit();
if (ql <= mid) tmp = tmp * Query(lson, ql, qr);
if (qr > mid) tmp = tmp * Query(rson, ql, qr);
*/
if(qr <= mid) return Query(lson, ql, qr);
if(ql > mid) return Query(rson, ql, qr);
return Query(lson, ql, qr) * Query(rson, ql, qr);
}
} T;
int n, m;
inline void Update(int pos, int uv) {
sub[pos].a[2][1] += - val[pos] + uv, val[pos] = uv;
Matrix bef, aft;
while (pos) {
bef = T.Query(1, 1, n, dfn[top[pos]], dfn[back[top[pos]]]);
T.Update(1, 1, n, dfn[pos]);
aft = T.Query(1, 1, n, dfn[top[pos]], dfn[back[top[pos]]]);
pos = fa[top[pos]];
sub[pos].a[1][2] = (sub[pos].a[1][1] += - max(bef.a[1][1], bef.a[2][1]) + max(aft.a[1][1], aft.a[2][1]));
sub[pos].a[2][1] += - bef.a[1][1] + aft.a[1][1];
}
}
inline int Query() {
Matrix tmp = T.Query(1, 1, n, dfn[1], dfn[back[top[1]]]);
return max(tmp.a[1][1], tmp.a[2][1]);
}
int main () {
File();
n = read(); m = read();
For (i, 1, n) val[i] = read();
For (i, 1, n - 1) { int u = read(), v = read(); G[u].push_back(v); G[v].push_back(u); }
Dfs_Init(1); Dfs_Part(1); Dp_Pre(1); T.Build(1, 1, n);
while (m --) {
int x = read(), y = read();
Update(x, y);
printf ("%d\n", Query());
}
//cerr << (double) clock() / CLOCKS_PER_SEC << endl;
return 0;
}
Luogu P4643 【模板】动态dp(矩阵乘法,线段树,树链剖分)的更多相关文章
- luogu P4719 【模板】动态 DP 矩阵乘法 + LCT
方法二:LCT+矩阵乘法 上文中,我们用线段树来维护重链上的各种矩阵转移. 第二种方法是将树链剖分替换为动态树. 我们知道,矩阵乘法 $\begin{bmatrix} F_{u,0} & F_ ...
- [luogu 4719][模板]动态dp
传送门 Solution \(f_{i,0}\) 表示以i节点为根的子树内,不选i号节点的最大独立集 \(f_{i,1}\)表示以i节点为根的子树内,选i号节点的最大独立集 \(g_{i,0}\) 表 ...
- 【bzoj2004】[Hnoi2010]Bus 公交线路 状压dp+矩阵乘法
题目描述 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计 ...
- 【bzoj3329】Xorequ 数位dp+矩阵乘法
题目描述 输入 第一行一个正整数,表示数据组数据 ,接下来T行每行一个正整数N 输出 2*T行第2*i-1行表示第i个数据中问题一的解, 第2*i行表示第i个数据中问题二的解, 样例输入 1 1 样例 ...
- BZOJ 1758 / Luogu P4292 [WC2010]重建计划 (分数规划(二分/迭代) + 长链剖分/点分治)
题意 自己看. 分析 求这个平均值的最大值就是分数规划,二分一下就变成了求一条长度在[L,R]内路径的权值和最大.有淀粉质的做法但是我没写,感觉常数会很大.这道题可以用长链剖分做. 先对树长链剖分. ...
- [模板] 动态dp
用途 对于某些树形dp(目前只会树上最大权独立集或者类似的),动态地修改点权,并询问修改后的dp值 做法(树剖版) 以最大权独立集为例 设$f[x][0/1]$表示x选不选,这棵子树的最大权独立集大小 ...
- 【BZOJ-4386】Wycieczki DP + 矩阵乘法
4386: [POI2015]Wycieczki Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 197 Solved: 49[Submit][Sta ...
- [模板][题解][Luogu1939]矩阵乘法加速递推(详解)
题目传送门 题目大意:计算数列a的第n项,其中: \[a[1] = a[2] = a[3] = 1\] \[a[i] = a[i-3] + a[i - 1]\] \[(n ≤ 2 \times 10^ ...
- THUSCH 2017 大魔法师(矩阵乘法+线段树)
题意 https://loj.ac/problem/2980 思路 区间修改考虑用线段树维护.由于一段区间的 \(A,B,C\) 可以表示成由原来的 \(A,B,C\) 乘上带上系数再加上某一个某个常 ...
随机推荐
- 亲测可以永久破解2018版本的pycharm
pycharm是很强大的开发工具,但是每次注册着实让人头疼.网络上很多注册码.注册服务器等等.但都只是一年或者不能用:为次有如下解决方案.亲测有效!!! 如果想让pycharm永久被激活,比如截止日到 ...
- Day8 Python基础之遗漏知识点(六)
1. 遗漏知识点 深.浅拷贝: http://www.cnblogs.com/yuanchenqi/articles/5782764.html a=b: 浅拷贝: 深拷贝 集合(set) 集合的定 ...
- iOS基于B站的IJKPlayer框架的流媒体探究
阅读数:6555 学习交流及技术讨论可新浪微博关注:极客James 一.流媒体 流媒体技术从传输形式上可以分为:渐进式下载和实施流媒体. 1.渐进式下载 它是介于实时播放和本地播放之间的一种播放方式, ...
- 【转】Docker部署Tomcat及Web应用
Docker部署Tomcat及Web应用 - Scofield_No1的博客 - CSDN博客https://blog.csdn.net/qq_32351227/article/details/786 ...
- Mysql中的排序规则utf8_unicode_ci、utf8_general_ci总结
Mysql中utf8_general_ci与utf8_unicode_ci有什么区别呢?在编程语言中,通常用unicode对中文字符做处理,防止出现乱码,那么在MySQL里,为什么大家都使用utf8_ ...
- # 【Python3练习题 003】一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?
# -------------------------------------------------## 所谓的“完全平方数”,就是开完根号仍然是整数.## 数学渣是这么思考的:假设这个数 i 在1 ...
- 便捷的ajax请求
为什么要做这个呢?如果后端给的数据不单有JSON字符串,还有对象呢?这个时候我们就要每个都处理(JSON.parse).万一后端又改了,所有都是对象呢?如此一来我们就需要对我们的ajax进行封装. 这 ...
- [转帖]Runtime, Engine, VM 的区别是什么?
这就是个WiFi和WLAN关系的问题嘛.Runtime是指用于支持程序运行时的组件,它可以是个Engine和/或VM.VM是一种系统抽象,它提供代码执行所需的API环境.Engine是一种处理抽象,它 ...
- jQuery EasyUI 折叠面板accordion的使用实例
1.对折叠面板区域 div 设置 class=”easyui-accordion” 2.在区域添加多个 div, 每个 div 就是一个面板 (每个面板一定要设置 title 属性). 3.设置面板属 ...
- 字符串正则替换replace第二个参数是函数
zepto中 //将字符串转成驼峰式的格式 camelize = function (str) { return str.replace(/-+(.)?/g, function (match, chr ...