国际惯例的题面:

这题......最大连通子块和显然可以DP,加上修改显然就是动态DP了......
考虑正常情况下怎么DP:
我们令a[i]表示选择i及i的子树中的一些点,最大连通子块和;
b[i]表示在i的子树中选择一些点(不一定包含i),最大连通子块和。
那么我们要询问i的子树的话,答案就是b[i]了。
考虑这个DP怎么转移,a[i]=max(sigma(j:SON_i)a[j]+v[i],0),b[i]=max((j:SON_i)b[j],a[i])。
陈俊锟说过,树上动态DP,就是把树拆成链,分离轻重儿子的转移。
于是我们重新定义DP:
f[i]表示从i所在的重链到i,选择连续一段和连续一段的子树,最大连通子块和(可以不包含i选择空段,类似a[i]);
g[i]表示计算i这个点本身和i的虚孩子们,形成的最大连续子块和。
dp[i]表示从i所在的重链到i,选择连续一段和连续一段的子树,或者从某个点的虚孩子中选择一个连通块,最大连通子块和(显然这个不一定包含i)。
这样的话,我们的转移就有:
g[i]=v[i]+sigma(j:LIGHTSON_i)f[j],f[i]=max(g[i]+f[HEAVYSON_i],0),dp[pos]=max(f[i],dp[HEAVYSON_i],max((j:LIGHTSON_i)dp[j]))。
这个转移初始化的话直接线性DP一遍就好了。
考虑怎么动态,这里的轻重孩子的转移都定义好了,我们只需要修改一些点的g和dp值,给他的父亲所在的重链当做输入值就好。
考虑怎么查询,如果是一条链的话,我们查询的就是最大子段和。树上的话,我们对于重链,也能查询g的最大子段和。
对于最优解不在这条链上的情况,我们用这个点的所有轻儿子的dp值去更新它单点的最大连续子段和就好,显然这是正确的。
也就是说,我们还需要维护一下DP值。考虑DP值是取max,所以用multiset去维护一下就好。
(其实这题我本来想写类似矩阵乘法的DP转移的,然后发现不会查询,于是只好分析题目性质列DP了)

代码:

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<set>
  4. using std::max;
  5. typedef long long int lli;
  6. const int maxn=2e5+1e2;
  7.  
  8. lli in[maxn],f[maxn],g[maxn],idp[maxn]; // f means from chain to top , g means cost of pos and virtualsons of pos , idp means max segment sum .
  9. int s[maxn],t[maxn<<],nxt[maxn<<];
  10. int dep[maxn],siz[maxn],fa[maxn],son[maxn],top[maxn],id[maxn],rec[maxn],mxd[maxn];
  11. std::multiset<lli> ls[maxn];
  12.  
  13. struct SegmentTree {
  14. int l[maxn<<],r[maxn<<],lson[maxn<<],rson[maxn<<],cnt;
  15. SegmentTree() { cnt = ; }
  16. struct Node {
  17. lli sl,sr,su,mx;
  18. friend Node operator + (const Node &a,const Node &b) {
  19. return (Node){max(a.sl,a.su+b.sl),max(a.sr+b.su,b.sr),a.su+b.su,max(a.sr+b.sl,max(a.mx,b.mx))};
  20. }
  21. inline void fil(int id) {
  22. sl = sr = max( g[rec[id]] , 0ll ) , su = g[rec[id]] , mx = max( g[rec[id]] , *ls[rec[id]].rbegin() );
  23. }
  24. }ns[maxn<<];
  25. inline void build(int pos,int ll,int rr) {
  26. l[pos] = ll , r[pos] = rr;
  27. if( ll == rr ) return ns[pos].fil(ll);
  28. const int mid = ( ll + rr ) >> ;
  29. build(lson[pos]=++cnt,ll,mid) , build(rson[pos]=++cnt,mid+,rr) ,
  30. ns[pos] = ns[lson[pos]] + ns[rson[pos]];
  31. }
  32. inline void update(int pos,const int &tar) {
  33. if( l[pos] == r[pos] ) return ns[pos].fil(tar);
  34. const int mid = ( l[pos] + r[pos] ) >> ;
  35. tar <= mid ? update(lson[pos],tar) : update(rson[pos],tar);
  36. ns[pos] = ns[lson[pos]] + ns[rson[pos]];
  37. }
  38. inline Node query(int pos,const int &ll,const int &rr) {
  39. if( ll <= l[pos] && r[pos] <= rr ) return ns[pos];
  40. const int mid = ( l[pos] + r[pos] ) >> ;
  41. if( rr <= mid ) return query(lson[pos],ll,rr);
  42. else if( ll > mid ) return query(rson[pos],ll,rr);
  43. else return query(lson[pos],ll,rr) + query(rson[pos],ll,rr);
  44. }
  45. }sgt;
  46. typedef SegmentTree::Node Node;
  47.  
  48. inline void addedge(int from,int to) {
  49. static int cnt = ;
  50. t[++cnt] = to , nxt[cnt] = s[from] , s[from] = cnt;
  51. }
  52. inline void pr(int pos) {
  53. siz[pos] = ;
  54. for(int at=s[pos];at;at=nxt[at]) if( t[at] != fa[pos] ) {
  55. fa[t[at]] = pos , dep[t[at]] = dep[pos] + , pr(t[at]) , siz[pos] += siz[t[at]];
  56. if( siz[t[at]] > siz[son[pos]] ) son[pos] = t[at];
  57. }
  58. }
  59. inline void pre(int pos) {
  60. static int iid;
  61. top[pos] = pos == son[fa[pos]] ? top[fa[pos]] : pos , rec[id[pos]=++iid] = pos , mxd[top[pos]] = iid , g[pos] = in[pos];
  62. if( son[pos] ) pre(son[pos]) , idp[pos] = idp[son[pos]] , f[pos] = f[son[pos]];
  63. for(int at=s[pos];at;at=nxt[at]) if( t[at] != fa[pos] && t[at] != son[pos] ) pre(t[at]) , g[pos] += f[t[at]] , ls[pos].insert(idp[t[at]]);
  64. f[pos] = max( f[pos] + g[pos] , 0ll ) , idp[pos] = max( idp[pos] , max( f[pos] , *ls[pos].rbegin() ) );
  65. }
  66.  
  67. inline Node query(int pos) {
  68. return sgt.query(,id[pos],mxd[top[pos]]);
  69. }
  70. inline void update(int pos,int nv) {
  71. Node od,nw;
  72. int fst = ;
  73. od.sl = in[pos] , nw.sl = nv , in[pos] = nv;
  74. while(pos) {
  75. g[pos] += nw.sl - od.sl;
  76. if( !fst ) ls[pos].erase(ls[pos].find(od.mx)) , ls[pos].insert(nw.mx);
  77. od = sgt.query(,id[top[pos]],mxd[top[pos]]) , sgt.update(,id[pos]) , nw = sgt.query(,id[top[pos]],mxd[top[pos]]);
  78. fst = , pos = fa[top[pos]];
  79. }
  80. }
  81.  
  82. int main() {
  83. static int n,m;
  84. static char o[];
  85. scanf("%d%d",&n,&m);
  86. for(int i=;i<=n;i++) scanf("%lld",in+i) , ls[i].insert();
  87. for(int i=,a,b;i<n;i++) scanf("%d%d",&a,&b) , addedge(a,b) , addedge(b,a);
  88. pr() , pre();
  89. sgt.build(,,n);
  90. for(int i=,x,y;i<=m;i++) {
  91. scanf("%s%d",o,&x);
  92. if( *o == 'M' ) scanf("%d",&y) , update(x,y);
  93. else printf("%lld\n",query(x).mx);
  94. }
  95. return ;
  96. }

いろ褪せたページの记忆
封存在褪色书页里的记忆
瞳闭じれば苏る
倘若闭上眼睛的话便会再度浮现
あどけない少女の祈り
少女那天真纯洁的祈望
羽ばたけよ 希望の空へ
振翅飞翔吧,向着希望的天空

叹く间もなく 时は流れる
时间在静静流逝,连叹息的时间也没有了
ひとり立ち止まるけど
但是却独身一人停下了脚步

5210: 最大连通子块和 动态DP 树链剖分的更多相关文章

  1. bzoj 5210 最大连通子块和——动态DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5210 似乎像bzoj4712一样,依然可以用别的方法做.但还是只写了动态DP. 当然是dp[ ...

  2. 6.3 省选模拟赛 Decompose 动态dp 树链剖分 set

    LINK:Decompose 看起来很难 实际上也很难 考验选手的dp 树链剖分 矩阵乘法的能力. 容易列出dp方程 暴力dp 期望得分28. 对于链的情况 容易发现dp方程可以转矩阵乘法 然后利用线 ...

  3. 【bzoj5210】最大连通子块和 动态dp

    动态$dp$好题 考虑用树链剖分将整棵树剖成若干条链. 设x的重儿子为$son[x]$,设$x$所在链链头为$top[x]$ 对于重链上的每个节点(不妨设该节点编号为$x$)令$f[x]$表示以$x$ ...

  4. BZOJ4712洪水——动态DP+树链剖分+线段树

    题目描述 小A走到一个山脚下,准备给自己造一个小屋.这时候,小A的朋友(op,又叫管理员)打开了创造模式,然后飞到 山顶放了格水.于是小A面前出现了一个瀑布.作为平民的小A只好老实巴交地爬山堵水.那么 ...

  5. bzoj5210 最大连通子块和 动态 DP + 堆

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5210 题解 令 \(dp[x][0]\) 表示以 \(x\) 为根的子树中的包含 \(x\) ...

  6. [HDU 5293]Tree chain problem(树形dp+树链剖分)

    [HDU 5293]Tree chain problem(树形dp+树链剖分) 题面 在一棵树中,给出若干条链和链的权值,求选取不相交的链使得权值和最大. 分析 考虑树形dp,dp[x]表示以x为子树 ...

  7. [2016北京集训试题7]thr-[树形dp+树链剖分+启发式合并]

    Description Solution 神仙操作orz. 首先看数据范围,显然不可能是O(n2)的.(即绝对不是枚举那么简单的),我们考虑dp. 定义f(x,k)为以x为根的子树中与x距离为k的节点 ...

  8. bzoj 5210: 最大连通子块和【动态dp+树剖+线段树+堆】

    参考:https://www.cnblogs.com/CQzhangyu/p/8632904.html 要开longlong的 首先看dp,设f[u]为必选u点的子树内最大联通块,p[u]为不一定选u ...

  9. 【BZOJ5210】最大连通子块和 树剖线段树+动态DP

    [BZOJ5210]最大连通子块和 Description 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块 ...

随机推荐

  1. 五、regularized线性回归练习(转载)

    转载链接:http://www.cnblogs.com/tornadomeet/archive/2013/03/17/2964515.html 前言: 本节主要是练习regularization项的使 ...

  2. 什么是 maven的uber-jar

    在maven的一些文档中我们会发现 "uber-jar"这个术语,许多人看到后感到困惑.其实在很多编程语言中会把super叫做uber (因为suber可能是关键字), 这是上世纪 ...

  3. 【转】assert预处理宏与预处理变量

    assert assert是一个预处理宏,由预处理器管理而非编译器管理,所以使用时都不用命名空间声明,如果你写成std::assert反而是错的.使用assert需要包含cassert或assert. ...

  4. 基于Golang设计一套微服务架构[转]

      article- @嘟嘟噜- May/26/2018 18:35:30 如何基于Golang设计一套微服务架构 微服务(Microservices),这个近几年我们经常听到.那么现在市面上的的微服 ...

  5. webstrom随手笔记

    1.node代码智能提示功能: 2.页面代码格式化快捷键: Ctrl+Alt+L键,或者Code =>Rearrange code

  6. LeetCode(52):N皇后 II

    Hard! 题目描述: n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击. 上图为 8 皇后问题的一种解法. 给定一个整数 n,返回 n 皇后不同的解决方 ...

  7. python 全栈开发,Day132(玩具管理页面,控制玩具通讯录,基于请求的好友关系建立)

    先下载github代码,下面的操作,都是基于这个版本来的! https://github.com/987334176/Intelligent_toy/archive/v1.5.zip 注意:由于涉及到 ...

  8. ASP.NET Global.asax详解【转】

    global.asax是一个文本文件,它提供全局可用代码.这些代码包括应用程序的事件处理程序以及会话事件.方法和静态变量.有时该文件也被称为应用程序文件. global.asax 文件中的任何代码都是 ...

  9. hdu 1010 走到终点时刚好花掉所有时间 (DFS + 奇偶性剪枝 )

    题意:输入一个n*m的迷宫,和一个T:可以在迷宫中生存的最大时间.S为起点,D为终点.并且,每个格子只能踩一次,且只能维持一秒,然后该块地板就会塌陷.所以你必须每秒走一步,且到D点时,所用时间为T.用 ...

  10. jsp+servlet实现最基本的注册登陆功能

    源码和数据库下载地址:http://download.csdn.net/detail/biexiansheng/9759722 1:首先需要设计好数据库和数据表,这里简单截图说明我创建的字段和类型. ...