题目分析:

解决了上次提到的《切树游戏》后,这道题就是一道模板题。

注意我们需要用堆维护子重链的最大值。这样不会使得复杂度变坏,因为每个重链我们只考虑一个点。

时间复杂度$O(nlog^2n)$

代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3.  
  4. typedef long long ll;
  5.  
  6. const int maxn = ;
  7.  
  8. int n,m;
  9. int v[maxn];
  10. vector<int> g[maxn];
  11. int fa[maxn],dep[maxn],sz[maxn],son[maxn],top[maxn],tail[maxn];
  12. int where[maxn],number[maxn],num;
  13. ll TOT[maxn];
  14.  
  15. struct Priority_queue{
  16. priority_queue <ll,vector<ll>,less<ll> > pq,del;
  17. void Insert(ll now){pq.push(now);}
  18. void Erase(ll now){del.push(now);}
  19. ll Top(){
  20. while(!del.empty()&&pq.top() == del.top()) pq.pop(),del.pop();
  21. return pq.top();
  22. }
  23. int Size(){return pq.size()-del.size();}
  24. }PQ[maxn];
  25.  
  26. struct node{ll L,R,D,C;}T[maxn<<];
  27.  
  28. void push_up(int now){
  29. T[now].L = max(T[now<<].L,T[now<<].C+T[now<<|].L);
  30. T[now].R = max(T[now<<|].R,T[now<<|].C+T[now<<].R);
  31. T[now].D = max(max(T[now<<].D,T[now<<|].D),T[now<<].R+T[now<<|].L);
  32. T[now].C = T[now<<].C+T[now<<|].C;
  33. }
  34.  
  35. node merge(node alpha,node beta){
  36. node gamma; gamma.L = max(alpha.L,alpha.C+beta.L);
  37. gamma.R = max(beta.R,beta.C+alpha.R);
  38. gamma.D = max(max(alpha.D,beta.D),alpha.R+beta.L);
  39. gamma.C = alpha.C+beta.C;
  40. return gamma;
  41. }
  42.  
  43. char readchar(){
  44. char ch = getchar(); while(ch != 'M' && ch != 'Q') ch = getchar();
  45. return ch;
  46. }
  47.  
  48. void read(){
  49. scanf("%d%d",&n,&m);
  50. for(int i=;i<=n;i++) scanf("%d",&v[i]);
  51. for(int i=;i<n;i++){
  52. int x,y; scanf("%d%d",&x,&y);
  53. g[x].push_back(y); g[y].push_back(x);
  54. }
  55. }
  56.  
  57. void dfs1(int now,int f,int dp){
  58. fa[now] = f; dep[now] = dp;
  59. for(int i=;i<g[now].size();i++){
  60. if(g[now][i] == f) continue;
  61. dfs1(g[now][i],now,dp+);
  62. sz[now] += sz[g[now][i]];
  63. if(son[now]==||sz[son[now]]<sz[g[now][i]])son[now]=g[now][i];
  64. }
  65. sz[now]++;
  66. if(son[now]) tail[now] = tail[son[now]];
  67. else tail[now] = now;
  68. }
  69.  
  70. void dfs2(int now,int tp){
  71. top[now] = tp;number[now] = ++num; where[num] = now;
  72. if(son[now]) dfs2(son[now],tp);
  73. for(int i=;i<g[now].size();i++){
  74. if(g[now][i] == fa[now] || g[now][i] == son[now]) continue;
  75. dfs2(g[now][i],g[now][i]);
  76. }
  77. }
  78.  
  79. void Modify(int now,int tl,int tr,int place){
  80. if(tl == tr){
  81. tl = where[tl];
  82. T[now].C = TOT[tl] + v[tl];
  83. T[now].L = max(0ll,TOT[tl]+v[tl]); T[now].R = T[now].L;
  84. if(PQ[tl].Size()) T[now].D = max(PQ[tl].Top(),T[now].L);
  85. else T[now].D = T[now].L;
  86. }else{
  87. int mid = (tl+tr)/;
  88. if(place <= mid) Modify(now<<,tl,mid,place);
  89. else Modify(now<<|,mid+,tr,place);
  90. push_up(now);
  91. }
  92. }
  93.  
  94. node Query(int now,int tl,int tr,int l,int r){
  95. if(tl >= l && tr <= r) return T[now];
  96. int mid = (tl+tr)/;
  97. if(r <= mid) return Query(now<<,tl,mid,l,r);
  98. if(l > mid) return Query(now<<|,mid+,tr,l,r);
  99. return merge(Query(now<<,tl,mid,l,r),Query(now<<|,mid+,tr,l,r));
  100. }
  101.  
  102. void dfs3(int now){
  103. if(son[now]) dfs3(son[now]);
  104. for(int i=;i<g[now].size();i++){
  105. int mp = g[now][i];
  106. if(mp == fa[now] || mp == son[now]) continue;
  107. dfs3(mp);
  108. PQ[now].Insert(Query(,,n,number[mp],number[tail[mp]]).D);
  109. }
  110. Modify(,,n,number[now]);
  111. if(top[now] == now){
  112. long long data = Query(,,n,number[now],number[tail[now]]).L;
  113. if(data > && fa[now]) TOT[fa[now]]+=data;
  114. }
  115. }
  116.  
  117. void work(){
  118. dfs1(,,);
  119. dfs2(,);
  120. dfs3();
  121. for(int i=;i<=m;i++){
  122. char ch = readchar();
  123. if(ch == 'M'){
  124. int x,y; scanf("%d%d",&x,&y);
  125. stack<int> sta; int now = top[x];
  126. while(fa[now]) sta.push(now),now = top[fa[now]];
  127. while(!sta.empty()){
  128. int mp = sta.top();sta.pop();
  129. node res = Query(,,n,number[mp],number[tail[mp]]);
  130. PQ[fa[mp]].Erase(res.D);
  131. if(res.L > ) TOT[fa[mp]]-=res.L;
  132. Modify(,,n,number[fa[mp]]);
  133. }
  134. now = x; v[x] = y;
  135. while(now){
  136. Modify(,,n,number[now]);
  137. now = top[now];
  138. node res = Query(,,n,number[now],number[tail[now]]);
  139. if(res.L > && fa[now]) TOT[fa[now]]+=res.L;
  140. PQ[fa[now]].Insert(res.D);
  141. now= fa[now];
  142. }
  143. }else{
  144. int x; scanf("%d",&x);
  145. long long ans = Query(,,n,number[x],number[tail[x]]).D;
  146. printf("%lld\n",ans);
  147. }
  148. }
  149. }
  150.  
  151. int main(){
  152. read();
  153. work();
  154. return ;
  155. }

BZOJ5210 最大连通子块和 【树链剖分】【堆】【动态DP】的更多相关文章

  1. 【bzoj5210】最大连通子块和 树链剖分+线段树+可删除堆维护树形动态dp

    题目描述 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块和. 其中,一棵子树的最大连通子块和指的是:该子树 ...

  2. 2019.02.15 bzoj5210: 最大连通子块和(链分治+ddp)

    传送门 题意:支持单点修改,维护子树里的最大连通子块和. 思路: 扯皮: bzojbzojbzoj卡常差评. 网上的题解大多用了跟什么最大子段和一样的转移方法. 但是我们实际上是可以用矩阵转移的传统d ...

  3. [bzoj4712]洪水 线段树+树链剖分维护动态dp+二分

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

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

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

  5. bzoj5210最大连通子块和 (动态dp+卡常好题)

    卡了一晚上,经历了被卡空间,被卡T,被卡数组等一堆惨惨的事情之后,终于在各位大爹的帮助下过了这个题qwqqq (全网都没有用矩阵转移的动态dp,让我很慌张) 首先,我们先考虑一个比较基础的\(dp\) ...

  6. Bzoj 2243: [SDOI2011]染色 树链剖分,LCT,动态树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 5020  Solved: 1872[Submit][Status ...

  7. BZOJ4538:[HNOI2016]网络(树链剖分,堆)

    Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做 一条树边.两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有 ...

  8. [树链剖分]BZOJ3589动态树

    题目描述 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0: 这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1: 小明希望你求出几条树枝上 ...

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

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

随机推荐

  1. elasticsearch简单操作(二)

    让我们建立一个员工目录,假设我们刚好在Megacorp工作,这时人力资源部门出于某种目的需要让我们创建一个员工目录,这个目录用于促进人文关怀和用于实时协同工作,所以它有以下不同的需求:1.数据能够包含 ...

  2. python四:函数练习--小白博客

    为什么要有函数?函数式编程定义一次,多出调用函数在一定程度上可以理解为变量函数的内存地址加上()就是调用函数本身也可以当做参数去传参 不用函数:组织结构不清晰代码的重复性 def test():#te ...

  3. Jq相关常用操作

    1.select下拉列表操作 $(".kstitle").live('change', function () { var workType = $(this).val(); // ...

  4. 使用faker去构造一个User-Agent

    faker可以仿造各种各样的信息,可以使用faker去构造一个User-Agent from faker import Factory f = Factory.create() 'User-Agent ...

  5. PS调出甜美艺术外景女生照片

    前期思路:拍摄时间大概在下午三四点左右,IOS100 f/1.8 .其实夏天最好的拍摄时间在傍晚五点这样,曝光太强片子会泛白,这张原片首先构图不是很好看,所以我要给它二次构图裁剪一下.下面是裁剪好后的 ...

  6. 09-babel

    这个是解析我们es6的代码的,为什么要用它呢,因为对于一些ie浏览器,甚至FF浏览器,低版本的还不能识别我们的es6代码,那么vue里面好多还让我们去写es6的代码,这个时候我们就可以用babel这个 ...

  7. centos安装bundle文件

    centos安装VMware-Workstation-Full-*.bundle那点事 | 鳗鱼是条狗https://kinggoo.com/centos-vmware.htm Linux 下 VMW ...

  8. 设置永久环境变量linux

    ========================================================================== http://www.cnblogs.com/Bi ...

  9. js 正则进阶regexp

    一.匹配中文,英文字母和数字及_: const reg = /^[\u4e00-\u9fa5\w]+$/; const str1 = 'shangyy'; const str2 = '尚悦悦ww123 ...

  10. C调用C++, C++调用C方法

    1. C 调用 C++封装好后的函数: -> 在C++中有一个函数 int main_cpp(): -> 首先构建头文件, #ifndef CPP_FILE_H   #define CPP ...