题意

我理解的动态DP:

发现DP可以写成矩阵的形式,因此用数据结构维护矩阵乘积。

对于这道题,显然有DP:

\(f_{x,0/1}\)表示\(x\)的子树中,x选/不选的最大点独立集。

\(f_{x,0}=\sum\limits_{y\in son_x}\max(f_{y,0},f_{y,1}),f_{x,1}=\sum\limits_{y\in sno_x}f_{y,0}+a_x\)

既然在树上,就用树剖或者LCT解决,本质都是将树拆成链,这里用树剖。

设\(son_x\)表示\(x\)的重儿子,\(g_{x,0/1}\)表示除去\(son_x\)后的\(f_{x,0}\)的值。

有:

\(f_{x,0}=g_{x,0}+\max(f_{son_x,0},f_{son_x,1}),f_{x,1}=g_{x,1}+f_{son_x,0}\),注意\(g_{x,1}\)初值为\(a_x\)。

DP写成矩阵的形式:

\(\begin{bmatrix}g_{x,0}&g_{x,0}\\g_{x,1}& 0\end{bmatrix}\begin{bmatrix}f_{y,0}\\ f_{y,1}\end{bmatrix}=\begin{bmatrix}f_{x,0}\\ f_{x,1}\end{bmatrix}\)

注意这里的矩乘长这样:

  1. Mat operator*(Mat a,Mat b)
  2. {
  3. Mat res;
  4. for(int i=1;i<=2;i++)
  5. for(int j=1;j<=2;j++)
  6. for(int k=1;k<=2;k++)
  7. res[i][j]=max(res[i][j],a[i][k]+b[k][j]);
  8. return res;
  9. }

之后就正常树剖修改查询即可

code:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define ls(p) (p<<1)
  4. #define rs(p) (p<<1|1)
  5. const int maxn=1e5+10;
  6. int n,m,cnt,tim;
  7. int head[maxn],a[maxn],size[maxn],pre[maxn],dep[maxn],son[maxn],dfn[maxn],pos[maxn],top[maxn],ed[maxn];
  8. int f[maxn][2];
  9. struct edge{int to,nxt;}e[maxn<<1];
  10. struct Mat
  11. {
  12. int a[5][5];
  13. Mat(){memset(a,-0x3f,sizeof(a));}
  14. int* operator[](int i){return a[i];}
  15. }val[maxn],seg[maxn<<2];
  16. Mat operator*(Mat a,Mat b)
  17. {
  18. Mat res;
  19. for(int i=1;i<=2;i++)
  20. for(int j=1;j<=2;j++)
  21. for(int k=1;k<=2;k++)
  22. res[i][j]=max(res[i][j],a[i][k]+b[k][j]);
  23. return res;
  24. }
  25. inline void add(int u,int v)
  26. {
  27. e[++cnt].nxt=head[u];
  28. head[u]=cnt;
  29. e[cnt].to=v;
  30. }
  31. void dfs1(int x,int fa)
  32. {
  33. dep[x]=dep[fa]+1;pre[x]=fa;size[x]=1;
  34. for(int i=head[x];i;i=e[i].nxt)
  35. {
  36. int y=e[i].to;
  37. if(y==fa)continue;
  38. dfs1(y,x);size[x]+=size[y];
  39. if(size[son[x]]<size[y])son[x]=y;
  40. }
  41. }
  42. void dfs2(int x,int tp)
  43. {
  44. dfn[x]=++tim;pos[tim]=x;top[x]=tp;ed[tp]=max(ed[tp],tim);
  45. f[x][0]=0,f[x][1]=a[x];
  46. val[x][1][1]=val[x][1][2]=0;
  47. val[x][2][1]=a[x];
  48. if(son[x])
  49. {
  50. dfs2(son[x],tp);
  51. f[x][0]+=max(f[son[x]][0],f[son[x]][1]);
  52. f[x][1]+=f[son[x]][0];
  53. }
  54. for(int i=head[x];i;i=e[i].nxt)
  55. {
  56. int y=e[i].to;
  57. if(y==pre[x]||y==son[x])continue;
  58. dfs2(y,y);
  59. f[x][0]+=max(f[y][0],f[y][1]);
  60. f[x][1]+=f[y][0];
  61. val[x][1][1]+=max(f[y][0],f[y][1]);
  62. val[x][1][2]=val[x][1][1];
  63. val[x][2][1]+=f[y][0];
  64. }
  65. }
  66. inline void up(int p){seg[p]=seg[ls(p)]*seg[rs(p)];}
  67. void build(int p,int l,int r)
  68. {
  69. if(l==r){seg[p]=val[pos[l]];return;}
  70. int mid=(l+r)>>1;
  71. build(ls(p),l,mid);build(rs(p),mid+1,r);
  72. up(p);
  73. }
  74. void change(int p,int l,int r,int k)
  75. {
  76. if(l==r){seg[p]=val[pos[k]];return;}
  77. int mid=(l+r)>>1;
  78. if(k<=mid)change(ls(p),l,mid,k);
  79. else change(rs(p),mid+1,r,k);
  80. up(p);
  81. }
  82. Mat query(int p,int l,int r,int ql,int qr)
  83. {
  84. if(l>=ql&&r<=qr)return seg[p];
  85. int mid=(l+r)>>1;
  86. if(qr<=mid)return query(ls(p),l,mid,ql,qr);
  87. else if(ql>mid)return query(rs(p),mid+1,r,ql,qr);
  88. else return query(ls(p),l,mid,ql,qr)*query(rs(p),mid+1,r,ql,qr);
  89. }
  90. inline void trchange(int x,int k)
  91. {
  92. val[x][2][1]+=k-a[x];
  93. a[x]=k;
  94. Mat tmp1,tmp2;
  95. while(x)
  96. {
  97. tmp1=query(1,1,n,dfn[top[x]],ed[top[x]]);
  98. change(1,1,n,dfn[x]);
  99. tmp2=query(1,1,n,dfn[top[x]],ed[top[x]]);
  100. x=pre[top[x]];
  101. val[x][1][1]+=max(tmp2[1][1],tmp2[2][1])-max(tmp1[1][1],tmp1[2][1]);
  102. val[x][1][2]=val[x][1][1];
  103. val[x][2][1]+=tmp2[1][1]-tmp1[1][1];
  104. }
  105. }
  106. int main()
  107. {
  108. scanf("%d%d",&n,&m);
  109. for(int i=1;i<=n;i++)scanf("%d",&a[i]);
  110. for(int i=1;i<n;i++)
  111. {
  112. int u,v;scanf("%d%d",&u,&v);
  113. add(u,v),add(v,u);
  114. }
  115. dfs1(1,0);dfs2(1,1);
  116. build(1,1,n);
  117. for(int i=1;i<=m;i++)
  118. {
  119. int x,y;scanf("%d%d",&x,&y);
  120. trchange(x,y);
  121. a[x]=y;
  122. Mat res=query(1,1,n,dfn[1],ed[1]);
  123. printf("%d\n",max(res[1][1],res[2][1]));
  124. }
  125. return 0;
  126. }

luoguP4719 【模板】动态 DP的更多相关文章

  1. [模板] 动态dp

    用途 对于某些树形dp(目前只会树上最大权独立集或者类似的),动态地修改点权,并询问修改后的dp值 做法(树剖版) 以最大权独立集为例 设$f[x][0/1]$表示x选不选,这棵子树的最大权独立集大小 ...

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

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

  3. luoguP4719 【模板】动态 DP 线段树+树链剖分+矩阵乘法+动态DP

    题目描述 给定一棵n个点的树,点带点权. 有m次操作,每次操作给定x,y,表示修改点x的权值为y. 你需要在每次操作之后求出这棵树的最大权独立集的权值大小. 输入输出格式 输入格式: 第一行,n,m分 ...

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

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

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

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

  6. Luogu P4643 【模板】动态dp

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

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

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

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

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

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

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

随机推荐

  1. 201871010126 王亚涛 《面向对象程序设计(java)》 第一周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/wyt0455820/ ...

  2. WPF 精修篇 用户控件

    原文:WPF 精修篇 用户控件 增加用户控件 数据绑定还是用依赖属性 使用的事件 就委托注册一下 public delegate void ButtonClick(object b,EventArgs ...

  3. bzoj5092 分割序列

    题目链接 problem 对于一个长度为n的非负整数序列\(b_1,b_2,...,b_n\),定义这个序列的能量为:\(f(b)=\max\limits_{i=0,1,...,n}(b_1 \oti ...

  4. Google工作法

    本文转自:https://www.yuque.com/heqingbao/msfy2c/zg56gm 这几天去上海参加Google开发者大会,利用空闲时间读了一本快餐书,书名叫<Google工作 ...

  5. LeetCode 387: 字符串中的第一个唯一字符 First Unique Character in a String

    题目: 给定一个字符串,找到它的第一个不重复的字符,并返回它的索引.如果不存在,则返回 -1. Given a string, find the first non-repeating charact ...

  6. pytest框架与unittest框架的对比

    一.pytest的优势 pytest是基于unittest之上的单元测试框架,它的优势如下: 自动发现测试模块和测试方法 断言使用 assert + 表达式 可以设置测试会话级(session).模块 ...

  7. PHP 扩展与 ZEND 引擎的整合

    PHP 扩展是对 PHP 功能的一个补充,编写完 PHP 扩展以后, ZEND 引擎需要获取到 PHP 扩展的信息,比如 phpinfo() 函数是如何列出 PHP 扩展的信息,PHP 扩展中的函数如 ...

  8. 数据库——SQL-SERVER练习(3)数据更新 视图

    (1).  将一个新学生记录(学号:95020:姓名:陈冬:性别:男:所在系:IS:年龄:18岁)插入到Student表中.(注意, 学号是主码不允许重复,一个学号只能插入一次,学号是5位数,不要用书 ...

  9. Redisson实现分布式锁(1)---原理

    Redisson实现分布式锁(1)---原理 有关Redisson作为实现分布式锁,总的分3大模块来讲. 1.Redisson实现分布式锁原理 2.Redisson实现分布式锁的源码解析 3.Redi ...

  10. .net core 后台如何生成html字符串到前台_后台html字符串在前台显示编码状态

    1-后台生成html字符串的方法一般是: this.ViewData.Add("CURRENCY_SYMBOLS", new HtmlString(JsonHelper.Conve ...