[模板] 动态dp
用途
对于某些树形dp(目前只会树上最大权独立集或者类似的),动态地修改点权,并询问修改后的dp值
做法(树剖版)
以最大权独立集为例
设$f[x][0/1]$表示x选不选,这棵子树的最大权独立集大小
那么有(设y是x的孩子)
$$f[x][0]=\sum{max\{f[y][0],f[y][1]\}} , f[x][1]=val[x]+\sum{f[y][0]}$$
那么在只关心其中的一个孩子y'的情况下,我们可以得到方程
$$f[x][0]=S_0+max\{f[y'][0],f[y'][1]\},f[x][1]=S_1+f[y'][0]$$
$S_0$和$S_1$的值参照上面的方程,它是与$f[y'][]$无关的
这样的话,我们修改$f[x][]$的值,这个转移的方程不会变 但是这并没有什么卵用
考虑用矩阵优化这个转移,先稍微变化一下转移的形式:
$$f[x][0]=max\{S_0+f[y'][0],S_0+f[y'][1]\},f[x][1]=max\{S_1+f[y'][0],-inf+f[y'][1]\}$$
然后我们发现,如果把矩阵乘法定义中的*变成+,+变成取max(即$c[i,j]=max\{a[i,k]+b[k,j]\}$),就可以把这个式子套进去
(这样做是有道理的,因为max和+满足交换律、结合律,max满足加法分配率)
就是说,x从y转移可以这样:
$$(f[x][0],f[x][1])=(f[y][0],f[y][1])* \left( \begin{matrix} S_0 & S_1 \\ S_0 & -\inf \end{matrix} \right) $$
然而各种孩子们变来变去的,并不能直接用这个
考虑用树剖来做:设$g[x]$为从x的重儿子转移到x的矩阵,为了方便,直接设$g[x][0]=S_0,g[x][1]=S_1$
这样的话,我修改一个点的f值,它的实父亲(?)的g值是不会变的
就是说,改的时候,只有到根的每条链的链顶的父亲的g值会改变(当然x自己的也会改变)
这个变是怎么变的呢,就是
$$g[x][0]+=max\{f_{new}[y][0],f_{new}[y][1]\}-max\{f_{old}[y][0],f_{old}[y][1]\} , g[x][1]+=f_{new}[y][0]-f_{old}[y][0] $$
(y是x的轻儿子)
那么我们改值的一个过程就可以写成这样:
1.求出top[x]原来的f值
2.修改x的g值
3.求出top[x]现在的f值
4.x=top[x]
然后我们发现,叶节点的g值其实就是它的f值,所以我们求一个点的f值的时候直接把矩阵从叶节点乘到这个点就可以了
最后的答案就是根节点的f值取个max
复杂度$O(mlog^2n$),我的常数好大啊
附代码(luogu4719)
- #include<bits/stdc++.h>
- #define CLR(a,x) memset(a,x,sizeof(a))
- using namespace std;
- typedef long long ll;
- typedef unsigned long long ull;
- typedef pair<int,int> pa;
- const int maxn=1e5+,inf=0x3f3f3f3f;
- inline ll rd(){
- ll x=;char c=getchar();int neg=;
- while(c<''||c>''){if(c=='-') neg=-;c=getchar();}
- while(c>=''&&c<='') x=x*+c-'',c=getchar();
- return x*neg;
- }
- struct Mat{
- int n,m,a[][];
- Mat(int x0=,int x1=,int x2=,int x3=,int x4=,int x5=){
- n=x0,m=x1,a[][]=x2,a[][]=x3,a[][]=x4,a[][]=x5;
- }
- }trans[maxn],g[maxn<<]; //从它的重儿子转移到它
- inline Mat operator *(Mat a,Mat b){
- if(a.n==) return b;
- if(b.n==) return a;
- Mat re=Mat(a.n,b.m,-inf,-inf,-inf,-inf);
- for(int i=;i<=re.n;i++){
- for(int j=;j<=re.m;j++){
- for(int k=;k<=a.m;k++){
- re.a[i][j]=max(re.a[i][j],a.a[i][k]+b.a[k][j]);
- }
- }
- }return re;
- }
- int N,M,eg[maxn*][],egh[maxn],ect,val[maxn];
- int fa[maxn],dep[maxn],dfn[maxn],tot,siz[maxn],wson[maxn],id[maxn],bot[maxn];
- int f[maxn][],top[maxn];
- inline void adeg(int a,int b){
- eg[++ect][]=b,eg[ect][]=egh[a],egh[a]=ect;
- }
- void dfs1(int x){
- f[x][]=,f[x][]=val[x];
- siz[x]=;
- for(int i=egh[x];i;i=eg[i][]){
- int b=eg[i][];if(b==fa[x]) continue;
- fa[b]=x,dep[b]=dep[x]+;
- dfs1(b);siz[x]+=siz[b];
- if(siz[b]>siz[wson[x]]) wson[x]=b;
- f[x][]+=max(f[b][],f[b][]);f[x][]+=f[b][];
- }
- int s=f[x][]-max(f[wson[x]][],f[wson[x]][]);
- int m=f[x][]-f[wson[x]][];
- trans[x]=Mat(,,s,m,s,-inf);
- }
- void dfs2(int x){
- dfn[x]=++tot;id[tot]=x;
- top[x]=(x==wson[fa[x]])?top[fa[x]]:x;
- if(wson[x]) dfs2(wson[x]);
- else bot[top[x]]=x;
- for(int i=egh[x];i;i=eg[i][]){
- int b=eg[i][];if(b==fa[x]||b==wson[x]) continue;
- dfs2(b);
- }
- }
- inline void build(int p,int l,int r){
- if(l==r) g[p]=trans[id[l]];
- else{
- int m=l+r>>;
- build(p<<,l,m);build(p<<|,m+,r);
- g[p]=g[p<<|]*g[p<<];
- }
- }
- inline void change(int p,int l,int r,int x,int d0,int d1){
- if(l==r){
- g[p].a[][]+=d0,g[p].a[][]+=d0,g[p].a[][]+=d1;
- }else{
- int m=l+r>>;
- if(x<=m) change(p<<,l,m,x,d0,d1);
- else change(p<<|,m+,r,x,d0,d1);
- g[p]=g[p<<|]*g[p<<];
- }
- }
- inline Mat query(int p,int l,int r,int x,int y){
- if(x<=l&&r<=y) return g[p];
- else{
- int m=l+r>>;Mat re=Mat();
- if(y>=m+) re=query(p<<|,m+,r,x,y);
- if(x<=m) re=re*query(p<<,l,m,x,y);
- return re;
- }
- }
- inline int update(int x,int y){
- Mat od,nw;
- while(x){
- int a,b;
- if(y) a=,b=y,y=;
- else{
- a=max(nw.a[][],nw.a[][])-max(od.a[][],od.a[][]);
- b=nw.a[][]-od.a[][];
- }
- od=query(,,N,dfn[top[x]],dfn[bot[top[x]]]);
- change(,,N,dfn[x],a,b);
- nw=query(,,N,dfn[top[x]],dfn[bot[top[x]]]);
- x=fa[top[x]];
- }
- return max(nw.a[][],nw.a[][]);
- }
- int main(){
- //freopen("","r",stdin);
- int i,j,k;
- N=rd(),M=rd();
- for(i=;i<=N;i++)
- val[i]=rd();
- for(i=;i<N;i++){
- int a=rd(),b=rd();
- adeg(a,b);adeg(b,a);
- }
- dep[]=;dfs1();
- dfs2();build(,,N);
- for(i=;i<=M;i++){
- int a=rd(),b=rd();
- printf("%d\n",update(a,b-val[a]));
- val[a]=b;
- }
- return ;
- }
[模板] 动态dp的更多相关文章
- [luogu 4719][模板]动态dp
传送门 Solution \(f_{i,0}\) 表示以i节点为根的子树内,不选i号节点的最大独立集 \(f_{i,1}\)表示以i节点为根的子树内,选i号节点的最大独立集 \(g_{i,0}\) 表 ...
- LG4719 【模板】动态dp 及 LG4751 动态dp【加强版】
题意 题目描述 给定一棵\(n\)个点的树,点带点权. 有\(m\)次操作,每次操作给定\(x,y\),表示修改点\(x\)的权值为\(y\). 你需要在每次操作之后求出这棵树的最大权独立集的权值大小 ...
- 洛谷P4719 【模板】"动态 DP"&动态树分治
[模板]"动态 DP"&动态树分治 第一道动态\(DP\)的题,只会用树剖来做,全局平衡二叉树什么的就以后再学吧 所谓动态\(DP\),就是在原本的\(DP\)求解的问题上 ...
- Luogu P4643 【模板】动态dp
题目链接 Luogu P4643 题解 猫锟在WC2018讲的黑科技--动态DP,就是一个画风正常的DP问题再加上一个动态修改操作,就像这道题一样.(这道题也是PPT中的例题) 动态DP的一个套路是把 ...
- 洛谷P4719 【模板】动态dp(ddp LCT)
题意 题目链接 Sol 动态dp板子题.有些细节还没搞懂,待我研究明白后再补题解... #include<bits/stdc++.h> #define LL long long using ...
- 【洛谷】P4643 【模板】动态dp
题解 在冬令营上听到冬眠的东西,现在都是板子了猫锟真的是好毒瘤啊(雾) (立个flag,我去thusc之前要把WC2018T1乱搞过去= =) 好的,我们可以参考猫锟的动态动态dp的课件,然后你发现你 ...
- 「LGP4719【模板】动态dp」
题目 尽管知道这个东西应该不会考了,但是还是学一学吧 哎要是去年noip之前学该多好 动态\(dp\)就是允许修改的一个\(dp\),比如这道题,我们都知道这是一个树上最大点权独立集 众所周知方程长这 ...
- 洛谷4719 【模板】动态dp
题目:https://www.luogu.org/problemnew/show/P4719 关于动态DP似乎有猫锟的WC2018论文,但找不见:还是算了. http://immortalco.blo ...
- P4719 【模板】动态dp
\(\color{#0066ff}{ 题目描述 }\) 给定一棵\(n\)个点的树,点带点权. 有\(m\)次操作,每次操作给定\(x,y\),表示修改点xx的权值为\(y\). 你需要在每次操作之后 ...
随机推荐
- 学习docker——命令总结
安装docker的方法可以参考:Ubuntu.CentOS.Windows.MacOS 查看版本信息 → ~ $ docker --version Docker version 18.03.1-ce, ...
- 熟悉pyspider的装饰器
熟悉pyspider的装饰器取经地点:https://segmentfault.com/a/1190000002477863 @config(age=10 * 24 * 60 * 60) 在这表示我们 ...
- MyBatis的demo
把以前写的关于mybatis的demo放在这边,以便查看. 目录结构: package com.test.mybatis.util; import java.io.IOException; impor ...
- java学习之—并归排序
/** * 并归排序 * Create by Administrator * 2018/6/26 0026 * 下午 5:13 **/ public class DArray { private lo ...
- 为linux主机增加file description
在benchmarked写的服务器的时候就遇到了too many file open 这个报错. 由于遇到过很多次了,所以知道应该是单机fd打满了. 首先来看看 机器最多支持多少fd cat /pro ...
- python3 阿里云控制SLB权重
一.配置好RAM账号的权限(SLB管理权限) 二.安装依赖 pip3 install aliyun-python-sdk-slb pip3 install aliyun-python-sdk-core ...
- ArcGIS 添加 MarkerSymbol 弹出“图形符号无法序列化为 JSON”错误
今天在做一个demo,向自定义图层中添加MarkerSymbol的时候,弹出“图形符号无法序列化为 JSON”错误,之前都没有出现过这个问题,我们首先来看一看我是怎样去添加图层,然后向图层中添加Gra ...
- Algorithm Visualizer
Algorithm Visualizer https://algorithm-visualizer.org/ https://algorithm-visualizer.org/divide-and-c ...
- 集合之TreeMap(含JDK1.8源码分析)
一.前言 前面所说的hashMap和linkedHashMap都不具备统计的功能,或者说它们的统计性能的时间复杂度都不是很好,要想对两者进行统计,需要遍历所有的entry,时间复杂度比较高,此时,我们 ...
- css3实现背景渐变
#grad { background: -webkit-linear-gradient(left,rgba(255,0,0,0),rgba(255,0,0,1)); /* Safari 5.1 - 6 ...