用途

对于某些树形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的更多相关文章

  1. [luogu 4719][模板]动态dp

    传送门 Solution \(f_{i,0}\) 表示以i节点为根的子树内,不选i号节点的最大独立集 \(f_{i,1}\)表示以i节点为根的子树内,选i号节点的最大独立集 \(g_{i,0}\) 表 ...

  2. LG4719 【模板】动态dp 及 LG4751 动态dp【加强版】

    题意 题目描述 给定一棵\(n\)个点的树,点带点权. 有\(m\)次操作,每次操作给定\(x,y\),表示修改点\(x\)的权值为\(y\). 你需要在每次操作之后求出这棵树的最大权独立集的权值大小 ...

  3. 洛谷P4719 【模板】"动态 DP"&动态树分治

    [模板]"动态 DP"&动态树分治 第一道动态\(DP\)的题,只会用树剖来做,全局平衡二叉树什么的就以后再学吧 所谓动态\(DP\),就是在原本的\(DP\)求解的问题上 ...

  4. Luogu P4643 【模板】动态dp

    题目链接 Luogu P4643 题解 猫锟在WC2018讲的黑科技--动态DP,就是一个画风正常的DP问题再加上一个动态修改操作,就像这道题一样.(这道题也是PPT中的例题) 动态DP的一个套路是把 ...

  5. 洛谷P4719 【模板】动态dp(ddp LCT)

    题意 题目链接 Sol 动态dp板子题.有些细节还没搞懂,待我研究明白后再补题解... #include<bits/stdc++.h> #define LL long long using ...

  6. 【洛谷】P4643 【模板】动态dp

    题解 在冬令营上听到冬眠的东西,现在都是板子了猫锟真的是好毒瘤啊(雾) (立个flag,我去thusc之前要把WC2018T1乱搞过去= =) 好的,我们可以参考猫锟的动态动态dp的课件,然后你发现你 ...

  7. 「LGP4719【模板】动态dp」

    题目 尽管知道这个东西应该不会考了,但是还是学一学吧 哎要是去年noip之前学该多好 动态\(dp\)就是允许修改的一个\(dp\),比如这道题,我们都知道这是一个树上最大点权独立集 众所周知方程长这 ...

  8. 洛谷4719 【模板】动态dp

    题目:https://www.luogu.org/problemnew/show/P4719 关于动态DP似乎有猫锟的WC2018论文,但找不见:还是算了. http://immortalco.blo ...

  9. P4719 【模板】动态dp

    \(\color{#0066ff}{ 题目描述 }\) 给定一棵\(n\)个点的树,点带点权. 有\(m\)次操作,每次操作给定\(x,y\),表示修改点xx的权值为\(y\). 你需要在每次操作之后 ...

随机推荐

  1. 【Python3练习题 025】 一个数,判断它是不是回文数。即12321是回文数,个位与万位相同,十位与千位相同

    [Python练习题 025] 一个5位数,判断它是不是回文数.即12321是回文数,个位与万位相同,十位与千位相同 x = input('请输入任意位数的数字:') if x == x[::-1]: ...

  2. C# List用法 List介绍

    一.#List泛型集合 集合是OOP中的一个重要概念,C#中对集合的全面支持更是该语言的精华之一. 为什么要用泛型集合? 在C# 2.0之前,主要可以通过两种方式实现集合: a.使用ArrayList ...

  3. jQuery EasyUI布局容器layout实例精讲

    这个布局容器,有五个区域:北.南.东.西和中心. 他中心地区面板是必需的,但是边缘地区面板是可选的.每一个边缘地区面板可以缩放的拖动其边境, 他们也可以通过点击其收缩触发.布局可以嵌套,从而用户可以建 ...

  4. php 生成订单号201807205598981

    php版 /** * 生成唯一订单号 */ public function build_order_no() { $no = date('Ymd').substr(implode(NULL, arra ...

  5. php变量详解

    变量是用于存储信息的"容器". 定义一个变量的语法: $变量名 = 值; 使用变量的例子: <?php $x=5; $y=6; $z=$x+$y; echo $z; ?> ...

  6. java使用顺序存储实现队列

    详细连接  https://blog.csdn.net/ljxbbss/article/details/78135993 操作系统:当电脑卡的时候,如果不停点击,还是卡死,最后终于电脑又好了以后,操作 ...

  7. Window上安装—Docker 笔记

    本文转自:http://cnodejs.org/topic/55a24267419f1e8a23a64367 需求 想玩nodeClub 源码跑起来,结果window 上各种报错,各种依赖软件要装的感 ...

  8. 莫烦theano学习自修第九天【过拟合问题与正规化】

    如下图所示(回归的过拟合问题):如果机器学习得到的回归为下图中的直线则是比较好的结果,但是如果进一步控制减少误差,导致机器学习到了下图中的曲线,则100%正确的学习了训练数据,看似较好,但是如果换成另 ...

  9. Redis 禁用FLUSHALL FLUSHDB KEYS 命令

      (error) ERR unknown command 'keys'问题解决(error) ERR unknown command 'FLUSHDB' 问题解决 背景 FLUSHALL FLUSH ...

  10. How to flash Havoc on enchilada

    update fastboot and adb fastboot oem unlock adb debug enchilada reboot to fastboot fastboot devices ...