其实就过了模板。

感觉就是带修改的dp

【模板】动态dp

给定一棵n个点的树,点带点权。

有m次操作,每次操作给定x,y表示修改点x的权值为y。

你需要在每次操作之后求出这棵树的最大权独立集的权值大小。

n,m<=1e5

参考题解:shadowice1984

n^2 DP简单又自然。

但是对于1e5次修改就不行了。

每一次修改会影响整个到根的链上的值。

采用树剖。

ldp[i][0/1]表示i选不选,对于所有的轻儿子dp值。

dp[i][0/1]表示i选不选,对于总共的所有儿子的dp值。

ldp[i][0]=∑max(ldp[lightson][1],ldp[lightson][0])

ldp[i][1]=∑ldp[lightson][0]

dp[i][0]=ldp[i][0]+max(dp[heavyson][1],dp[heavyson][0])

dp[i][1]=ldp[i][1]+dp[heavyson][0]

可以先把这个dp都求出来。

然后怎么维护?自然要用线段树维护dfs序。

采用矩阵。

a*b定义为:

c[i][j]=max(a[i][k]+b[k][j])

有结合律。

线段树维护区间矩阵乘积。(注意从右往左乘,自下而上)

只要在最前面乘上一个初始矩阵

第一行是0,第二行是-inf的矩阵。

就可以求出某个点的最终dp值了。

修改的时候,暴力修改这个 点的ldp0,ldp1

但是还会影响这个fa[top[x]]的ldp0,ldp1

所以要求出dp[top[x]],dp[top[y]]为了避免常数过大,

用一个数组记录dp值,然后把前后两次最大值的差值来修改fa[top[x]]的ldp0,ldp1

然后跳一条链,到fa[top[x]]

这样单次修改log^2n

每次返回max(dp[1][0],dp[1][1])

普通线段树版:(3000ms)

  1. #include<bits/stdc++.h>
  2. #define reg register int
  3. #define il inline
  4. #define numb (ch^'0')
  5. #define mid ((l+r)>>1)
  6. using namespace std;
  7. typedef long long ll;
  8. il void rd(int &x){
  9. char ch;x=;bool fl=false;
  10. while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
  11. for(x=numb;isdigit(ch=getchar());x=x*+numb);
  12. (fl==true)&&(x=-x);
  13. }
  14. namespace Miracle{
  15. const int N=1e5+;
  16. const int inf=0x3f3f3f3f;
  17. int n,m;
  18. struct node{
  19. int nxt,to;
  20. }e[*N];
  21. int hd[N],cnt;
  22. void add(int x,int y){
  23. e[++cnt].nxt=hd[x];
  24. e[cnt].to=y;
  25. hd[x]=cnt;
  26. }
  27. struct tr{
  28. int a[][];
  29. void init(int x,int y){//x:ldp0 y:ldp1
  30. a[][]=x,a[][]=x;
  31. a[][]=y,a[][]=-inf;
  32. }
  33. void pre(){
  34. memset(a,-inf,sizeof a);
  35. }
  36. void st(){
  37. a[][]=,a[][]=-inf,a[][]=-inf,a[][]=;
  38. }
  39. tr operator *(const tr& b){
  40. tr c;c.pre();
  41. for(reg i=;i<=;++i){
  42. for(reg k=;k<=;++k){
  43. for(reg j=;j<=;++j){
  44. c.a[i][j]=max(c.a[i][j],a[i][k]+b.a[k][j]);
  45. }
  46. }
  47. }return c;
  48. }
  49. void op(){
  50. cout<<left<<setw()<<a[][]<<" "<<left<<setw()<<a[][]<<endl;
  51. cout<<left<<setw()<<a[][]<<" "<<left<<setw()<<a[][]<<endl;
  52. cout<<endl;
  53. }
  54. }s[N],t[*N],A;
  55. int dfn[N],top[N],dfn2[N],fdfn[N],sz[N],dep[N],son[N];
  56. int nd[N];//tot;//num of heavy chain
  57. int fa[N];
  58. int df;
  59. int ldp[N][],dp[N][];
  60. int w[N];
  61. void dfs1(int x,int d){
  62. dep[x]=d;
  63. sz[x]=;
  64. for(reg i=hd[x];i;i=e[i].nxt){
  65. int y=e[i].to;
  66. if(y==fa[x]) continue;
  67. fa[y]=x;
  68. dfs1(y,d+);
  69. if(sz[y]>sz[son[x]]){
  70. son[x]=y;
  71. }
  72. }
  73. }
  74. void dfs2(int x){
  75. dfn[x]=++df;fdfn[df]=x;
  76. if(!top[x]) {
  77. top[x]=x;nd[top[x]]=x;
  78. }
  79. if(son[x]) top[son[x]]=top[x],nd[top[x]]=son[x],dfs2(son[x]);
  80.  
  81. dp[x][]=w[x];
  82. ldp[x][]=w[x];
  83. for(reg i=hd[x];i;i=e[i].nxt){
  84. int y=e[i].to;
  85. if(y==son[x]||y==fa[x]) continue;
  86. dfs2(y);
  87. ldp[x][]+=max(dp[y][],dp[y][]);
  88. ldp[x][]+=dp[y][];
  89. }
  90. if(son[x]){
  91. dp[x][]=ldp[x][]+dp[son[x]][];
  92. dp[x][]=ldp[x][]+max(dp[son[x]][],dp[son[x]][]);
  93. }
  94. s[x].init(ldp[x][],ldp[x][]);
  95. }
  96. void pushup(int x){
  97. t[x]=t[x<<|]*t[x<<];
  98. }
  99. void build(int x,int l,int r){
  100. if(l==r){
  101. t[x]=s[fdfn[l]];return;
  102. }
  103. build(x<<,l,mid);build(x<<|,mid+,r);
  104. pushup(x);
  105. }
  106. tr query(int x,int l,int r,int L,int R){
  107. if(L<=l&&r<=R){
  108. return t[x];
  109. }
  110. tr ret;ret.st();
  111. if(mid<R) ret=ret*query(x<<|,mid+,r,L,R);
  112. if(L<=mid) ret=ret*query(x<<,l,mid,L,R);
  113. return ret;
  114. }
  115. void add(int x,int l,int r,int to,int p,int c){
  116. if(l==r){
  117. if(p) t[x].a[][]+=c;
  118. else t[x].a[][]+=c,t[x].a[][]+=c;
  119. return;
  120. }
  121. if(to<=mid) add(x<<,l,mid,to,p,c);
  122. else if(mid<to) add(x<<|,mid+,r,to,p,c);
  123. pushup(x);
  124. }
  125. int tmp[];
  126. int to[];
  127. int upda(int x,int y){
  128. tmp[]=tmp[]=;
  129. to[]=to[]=;
  130. tmp[]=y-w[x];
  131. w[x]=y;
  132. while(x){
  133. tr anc=A*query(,,n,dfn[top[x]],dfn[nd[top[x]]]);
  134. to[]=anc.a[][],to[]=anc.a[][];
  135. add(,,n,dfn[x],,tmp[]);
  136. add(,,n,dfn[x],,tmp[]);
  137. anc=A*query(,,n,dfn[top[x]],dfn[nd[top[x]]]);
  138. tmp[]=max(anc.a[][],anc.a[][])-max(to[],to[]);
  139. tmp[]=anc.a[][]-to[];
  140. x=fa[top[x]];
  141. }
  142. tr ans=A*query(,,n,dfn[top[]],dfn[nd[top[]]]);
  143. return max(ans.a[][],ans.a[][]);
  144. }
  145. int main(){
  146. scanf("%d%d",&n,&m);
  147. for(reg i=;i<=n;++i)rd(w[i]);
  148. int x,y;
  149. for(reg i=;i<=n-;++i){
  150. rd(x);rd(y);add(x,y);add(y,x);
  151. }
  152. dfs1(,);
  153. dfs2();
  154. build(,,n);
  155. A.a[][]=,A.a[][]=;
  156. A.a[][]=-inf,A.a[][]=-inf;
  157. while(m--){
  158. rd(x);rd(y);
  159. printf("%d\n",upda(x,y));
  160. }
  161. return ;
  162. }
  163.  
  164. }
  165. int main(){
  166. Miracle::main();
  167. return ;
  168. }
  169.  
  170. /*
  171. Author: *Miracle*
  172. Date: 2018/11/12 16:29:49
  173. */

zkw线段树版:(1500ms)

  1. #include<bits/stdc++.h>
  2. #define reg register int
  3. #define il inline
  4. #define numb (ch^'0')
  5. #define mid ((l+r)>>1)
  6. using namespace std;
  7. typedef long long ll;
  8. il void rd(int &x){
  9. char ch;x=;bool fl=false;
  10. while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
  11. for(x=numb;isdigit(ch=getchar());x=x*+numb);
  12. (fl==true)&&(x=-x);
  13. }
  14. namespace Miracle{
  15. const int N=1e5+;
  16. const int inf=0x3f3f3f3f;
  17. int n,m;
  18. struct node{
  19. int nxt,to;
  20. }e[*N];
  21. int hd[N],cnt;
  22. il void add(int x,int y){
  23. e[++cnt].nxt=hd[x];
  24. e[cnt].to=y;
  25. hd[x]=cnt;
  26. }
  27. struct tr{
  28. int a[][];
  29. void init(int x,int y){//x:ldp0 y:ldp1
  30. a[][]=x,a[][]=x;
  31. a[][]=y,a[][]=-inf;
  32. }
  33. void pre(){
  34. memset(a,-inf,sizeof a);
  35. }
  36. void st(){
  37. a[][]=,a[][]=-inf,a[][]=-inf,a[][]=;
  38. }
  39. tr operator *(const tr& b) const{
  40. tr c;c.pre();
  41. for(reg i=;i<=;++i){
  42. for(reg k=;k<=;++k){
  43. for(reg j=;j<=;++j){
  44. c.a[i][j]=max(c.a[i][j],a[i][k]+b.a[k][j]);
  45. }
  46. }
  47. }return c;
  48. }
  49. void op(){
  50. cout<<left<<setw()<<a[][]<<" "<<left<<setw()<<a[][]<<endl;
  51. cout<<left<<setw()<<a[][]<<" "<<left<<setw()<<a[][]<<endl;
  52. cout<<endl;
  53. }
  54. }s[N],t[*N],A;
  55. int dfn[N],top[N],dfn2[N],fdfn[N],sz[N],dep[N],son[N];
  56. int nd[N];//tot;//num of heavy chain
  57. int fa[N];
  58. int df;
  59. int ldp[N][],dp[N][];
  60. int w[N];
  61. il void dfs1(int x,int d){
  62. dep[x]=d;
  63. sz[x]=;
  64. for(reg i=hd[x];i;i=e[i].nxt){
  65. int y=e[i].to;
  66. if(y==fa[x]) continue;
  67. fa[y]=x;
  68. dfs1(y,d+);
  69. if(sz[y]>sz[son[x]]){
  70. son[x]=y;
  71. }
  72. }
  73. }
  74. il void dfs2(int x){
  75. dfn[x]=++df;fdfn[df]=x;
  76. if(!top[x]) {
  77. top[x]=x;nd[top[x]]=x;
  78. }
  79. if(son[x]) top[son[x]]=top[x],nd[top[x]]=son[x],dfs2(son[x]);
  80.  
  81. dp[x][]=w[x];
  82. ldp[x][]=w[x];
  83. for(reg i=hd[x];i;i=e[i].nxt){
  84. int y=e[i].to;
  85. if(y==son[x]||y==fa[x]) continue;
  86. dfs2(y);
  87. ldp[x][]+=max(dp[y][],dp[y][]);
  88. ldp[x][]+=dp[y][];
  89. }
  90. if(son[x]){
  91. dp[x][]=ldp[x][]+dp[son[x]][];
  92. dp[x][]=ldp[x][]+max(dp[son[x]][],dp[son[x]][]);
  93. }
  94. s[x].init(ldp[x][],ldp[x][]);
  95. }
  96. int up;
  97. il void build(){
  98. up=;
  99. for(;up<=n+;up<<=);
  100. for(reg i=up;i<=up+up-;++i){
  101. if(i>=up+&&i<=up+n) t[i]=s[fdfn[i-up]];
  102. else t[i]=A;
  103. }
  104. for(reg i=up-;i;--i) t[i]=t[i<<|]*t[i<<];
  105. }
  106. il void chan(int to,int c0,int c1){
  107. reg i=up+to;
  108. t[i].a[][]+=c0;t[i].a[][]+=c0;
  109. t[i].a[][]+=c1;
  110. for(i>>=;i;i>>=){
  111. t[i]=t[i<<|]*t[i<<];
  112. }
  113. // cout<<" after chan "<<endl;
  114. }
  115. il tr query(int l,int r){
  116. tr le,ri;le.st();ri.st();
  117. for(reg s=up+l-,e=up+r+;s^e^;s>>=,e>>=){
  118. // cout<<s<<" "<<e<<endl;
  119. if(!(s&)) le=t[s^]*le;
  120. if(e&) ri=ri*t[e^];
  121. }
  122. return ri*le;
  123. }
  124. int tmp[];
  125. int to[];
  126. il int upda(int x,int y){
  127. tmp[]=tmp[]=;
  128. to[]=to[]=;
  129. tmp[]=y-w[x];
  130. w[x]=y;
  131. while(x){
  132. //tr anc=A*query(1,1,n,dfn[top[x]],dfn[nd[top[x]]]);
  133. to[]=dp[top[x]][],to[]=dp[top[x]][];
  134. chan(dfn[x],tmp[],tmp[]);
  135. tr anc=A*query(dfn[top[x]],dfn[nd[top[x]]]);
  136. tmp[]=max(anc.a[][],anc.a[][])-max(to[],to[]);
  137. tmp[]=anc.a[][]-to[];
  138. dp[top[x]][]=anc.a[][],dp[top[x]][]=anc.a[][];
  139. x=fa[top[x]];
  140. }
  141. return max(dp[][],dp[][]);
  142. }
  143. int main(){
  144. scanf("%d%d",&n,&m);
  145. for(reg i=;i<=n;++i)rd(w[i]);
  146. int x,y;
  147. for(reg i=;i<=n-;++i){
  148. rd(x);rd(y);add(x,y);add(y,x);
  149. }
  150. dfs1(,);
  151. dfs2();
  152. A.a[][]=,A.a[][]=;
  153. A.a[][]=-inf,A.a[][]=-inf;
  154. build();
  155. while(m--){
  156. rd(x);rd(y);
  157. printf("%d\n",upda(x,y));
  158. }
  159. return ;
  160. }
  161.  
  162. }
  163. int main(){
  164. // freopen("data.in","r",stdin);
  165. // freopen("my.out","w",stdout);
  166. Miracle::main();
  167. return ;
  168. }
  169.  
  170. /*
  171. Author: *Miracle*
  172. Date: 2018/11/12 16:29:49
  173. */

[学习笔记]动态dp的更多相关文章

  1. WPF-学习笔记 动态修改控件Margin的值

    原文:WPF-学习笔记 动态修改控件Margin的值 举例说明:动态添加一个TextBox到Grid中,并设置它的Margin: TextBox text = new TextBox(); t_gri ...

  2. Java学习笔记——动态代理

    所谓动态,也就是说这个东西是可变的,或者说不是一生下来就有的.提到动态就不得不说静态,静态代理,个人觉得是指一个代理在程序中是事先写好的,不能变的,就像上一篇"Java学习笔记——RMI&q ...

  3. Angular 学习笔记 (动态组件 & Material Overlay & Dialog 分析)

    更新: 2019-11-24  dialog vs router link refer : https://stackoverflow.com/questions/51821766/angular-m ...

  4. [学习笔记]整体DP

    问题: 有一些问题,通常见于二维的DP,另一维记录当前x的信息,但是这一维过大无法开下,O(nm)也无法通过. 但是如果发现,对于x,在第二维的一些区间内,取值都是相同的,并且这样的区间是有限个,就可 ...

  5. [学习笔记] 数位DP的dfs写法

    跟着洛谷日报走,算法习题全都有! 嗯,没错,这次我也是看了洛谷日报的第84期才学会这种算法的,也感谢Mathison大佬,素不相识,却写了一长篇文章来帮助我学习这个算法. 算法思路: 感觉dfs版的数 ...

  6. 学习笔记-动态树Link-Cut-Tree

    --少年你有梦想吗? --少年你听说过安利吗? 安利一个集训队讲解:http://wenku.baidu.com/view/75906f160b4e767f5acfcedb 关于动态树问题,有多种方法 ...

  7. [WPF学习笔记]动态加载XAML

    好久没写Blogs了,现在在看[WPF编程宝典],决定开始重新写博客,和大家一起分享技术. 在编程时我们常希望界面是动态的,可以随时变换而不需要重新编译自己的代码. 以下是动态加载XAML的一个事例代 ...

  8. 单片机C语言开发学习笔记---动态的数码管

    在郭天祥的那本书中,有一个通过按键控制数码管的例子,在运行这个例子的时候,我发现当按键按下的时候,第一位数码管会熄掉,这是为什么呢? 后来在网上找到了原因,当我按下按键不松开的时候,接下来要运行的代码 ...

  9. EXCEL 2010学习笔记—— 动态图表

    今天梳理一下动态图表的相关内容,做一个简单的整理 关键的操作点: 1.插入动态控制器:开发工具->插入->表单控件 对控件进行修改  右键 设置控件格式->单元格链接 用来作为if ...

随机推荐

  1. C# Winform WebBrowser控件

    C# WinForm WebBrowser 1.主要用途:使用户可以在窗体中导航网页. 2.注意:WebBrowser 控件会占用大量资源.使用完该控件后一定要调用 Dispose 方法,以便确保及时 ...

  2. 数据分析处理库Pandas——常用操作

    DataFrame结构排序 备注:group列降序,data列升序. 合并相同项 查找相同项 添加一列,值是其他列的值进行相关操作后的值 删除列 Series结构替换值 一组值按照范围归类 归类后每类 ...

  3. python学习——函数

     一.在python的世界里什么是函数: 答:函数通常是用来实现某一个功能二被封装成的一个对象,是用来实现代码复用的常用方式 现在有一个需求,假如你在不知道len()方法的情况下,要你计算字符串‘he ...

  4. 实验吧编程题python

    网址:http://ctf5.shiyanbar.com/jia 之后第一步就是刷新一下网页,发现给的公式会变,(废话,要不直接算数不就行了...)但是格式不会变. 所以那就暴力一点好了,我们看一下这 ...

  5. 谭浩强第四版第九章课后习题12>>>建立一个链表,每个节点包括:学号、姓名、性别、年龄。输入一个年龄,若链表 中的结点所包含的年龄等于此年龄,则删除此结点。

    #include<stdio.h> #include<stdlib.h> #define N sizeof(link) typedef struct lin { struct ...

  6. 深入了解jQuery Mobile-3装载器

    介绍 当jQuery Mobile通过Ajax加载内容或用于自定义通知时,会显示一个小的加载叠加层. 标准loader $( document ).on( "click", &qu ...

  7. LeetCode:21. Merge Two Sorted Lists(Easy)

    1. 原题链接 https://leetcode.com/problems/merge-two-sorted-lists/description/ 2. 题目要求 给出两个已经从小到大排序的链表ls1 ...

  8. DDoS 攻击与防御:从原理到实践(下)

    欢迎访问网易云社区,了解更多网易技术产品运营经验. DDoS 攻击与防护实践 DDoS 攻击的实现方式主要有如下两种: 自建 DDoS 平台 现在有开源的 DDoS 平台源代码,只要有足够机器和带宽资 ...

  9. [电子书] 《Android编程兵书》PDF

    Android编程兵书 内容简介: 这是一本Android开发书籍,内容讲解详细,例子丰富,能帮助读者举一反三.在<Android编程兵书>中,每一个知识点的描述都非常详细,并且每一个知识 ...

  10. react children技巧总结

    在使用该技巧时,建议先看一下相关的知识,点我查看 假如使用该属性时,想把父组件的所有属性及部分方法传递给子组件,该怎么办呢?看代码 const Child = ({ doSomething, valu ...