题目分析:

不难发现可以用动态DP做。

题目相当于是要我求一条路径,所有与路径有交的链的代价加入进去,要求代价最大。

我们把链的代价分成两个部分:一部分将代价加入$LCA$之中,用$g$数组保存;另一部分将代价加在整条链上,用$d$数组保存。

这时候我们可以发现,一条从$u$到$v$的路径的代价相当于是$d[LCA(u,v)]+\sum_{x \in edge(u,v)}g[x]$。

如果是静态的,可以用树形DP解决。

看过《神奇的子图》的同学都知道,叶子结点是从它的儿子中取两个最大的出来,所以堆维护。

考虑合并。

链从左延申出的最大的$g$的总和记录。链从右延申包括$d$的总和记录,每次向上$update$的时候拼起来与原答案比较即可。

代码:

  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.  
  10. vector <int> g[maxn];
  11. int sz[maxn],top[maxn],fa[maxn],dep[maxn],son[maxn],ind[maxn],dr[maxn];
  12. int tail[maxn],num;
  13.  
  14. struct Query{int from,to,w;}Q[maxn];
  15. struct Priority_Queue{
  16. priority_queue<ll,vector<ll>,less<ll> > pq,del;
  17. void push(ll now){pq.push(now);}
  18. void pop(){
  19. while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop();
  20. pq.pop();
  21. }
  22. ll top(){
  23. while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop();
  24. if(pq.empty()) return ;
  25. else return pq.top();
  26. }
  27. ll sec(){
  28. while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop();
  29. if(pq.size() ==) return ;
  30. ll oop = pq.top(); pq.pop();
  31. while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop();
  32. if(pq.size() == ){pq.push(oop);return ;}
  33. else {ll ret = pq.top();pq.push(oop);return ret;}
  34. }
  35. void Erase(ll now){del.push(now);}
  36. }Son[maxn],Ans;
  37.  
  38. struct segmentTree{
  39. ll tg,ff,lazy,REC,L,R;
  40. }T[maxn<<];
  41.  
  42. void push_down(int now){
  43. T[now<<].ff += T[now].lazy; T[now<<|].ff += T[now].lazy;
  44. T[now<<].REC += T[now].lazy; T[now<<|].REC += T[now].lazy;
  45. T[now<<].lazy += T[now].lazy; T[now<<|].lazy += T[now].lazy;
  46. T[now<<].R += T[now].lazy; T[now<<|].R += T[now].lazy;
  47. T[now].lazy = ;
  48. }
  49.  
  50. segmentTree merge(segmentTree alpha,segmentTree beta){
  51. segmentTree RES;RES.lazy = ; RES.ff = ;
  52. RES.tg = alpha.tg + beta.tg;
  53. RES.REC = max(alpha.REC,beta.REC);
  54. RES.REC = max(RES.REC,alpha.R + beta.L);
  55. RES.L = max(alpha.L,alpha.tg + beta.L);
  56. RES.R = max(beta.R,alpha.R + beta.tg);
  57. return RES;
  58. }
  59.  
  60. void dfs1(int now,int f,int dp){
  61. dep[now] = dp; fa[now] = f;
  62. int maxx = ;
  63. for(auto it:g[now]){
  64. if(it == f) continue;
  65. dfs1(it,now,dp+);
  66. sz[now] += sz[it];
  67. if(maxx == || sz[it] > sz[maxx]) maxx = it;
  68. }
  69. son[now] = maxx; sz[now]++;
  70. }
  71.  
  72. void dfs2(int now,int tp){
  73. top[now] = tp; ind[now] = ++num; dr[num] = now;
  74. if(now == tp) Ans.push();
  75. if(son[now]) dfs2(son[now],tp);
  76. else tail[tp] = now;
  77. for(auto it : g[now]){
  78. if(it == fa[now] || it == son[now]) continue;
  79. dfs2(it,it);
  80. }
  81. }
  82.  
  83. void read(){
  84. scanf("%d%d",&n,&m);
  85. for(int i=;i<n;i++){
  86. int u,v; scanf("%d%d",&u,&v);
  87. g[u].push_back(v); g[v].push_back(u);
  88. }
  89. }
  90.  
  91. int QueryLca(int u,int v){
  92. while(top[u] != top[v]){
  93. if(dep[top[u]] > dep[top[v]]) u = fa[top[u]];
  94. else v = fa[top[v]];
  95. }
  96. if(dep[u] < dep[v]) return u; else return v;
  97. }
  98.  
  99. segmentTree Querylen(int now,int tl,int tr,int l,int r){
  100. if(tl >= l && tr <= r) return T[now];
  101. if(T[now].lazy) push_down(now);
  102. int mid = (tl+tr)/;
  103. if(mid < l) return Querylen(now<<|,mid+,tr,l,r);
  104. if(mid >= r) return Querylen(now<<,tl,mid,l,r);
  105. segmentTree pp = Querylen(now<<|,mid+,tr,l,r);
  106. segmentTree qq = Querylen(now<<,tl,mid,l,r);
  107. return merge(qq,pp);
  108. }
  109.  
  110. void AddG(int now,int tl,int tr,int place,int w){
  111. if(tl == tr){T[now].tg += w;T[now].L += w;return;}
  112. if(T[now].lazy) push_down(now);
  113. int mid = (tl+tr)/;
  114. if(mid >= place) AddG(now<<,tl,mid,place,w);
  115. else AddG(now<<|,mid+,tr,place,w);
  116. T[now] = merge(T[now<<],T[now<<|]);
  117. }
  118.  
  119. void ModifyG(int now,int tl,int tr,int place){
  120. if(tl == tr){
  121. tl = dr[tl]; T[now].L = Son[tl].top() + T[now].tg;
  122. T[now].REC = T[now].ff + Son[tl].top() + Son[tl].sec();
  123. T[now].R = T[now].ff + Son[tl].top();
  124. return;
  125. }
  126. if(T[now].lazy) push_down(now);
  127. int mid = (tl+tr)/;
  128. if(mid >= place) ModifyG(now<<,tl,mid,place);
  129. else ModifyG(now<<|,mid+,tr,place);
  130. T[now] = merge(T[now<<],T[now<<|]);
  131. }
  132.  
  133. void ModifyF(int now,int tl,int tr,int l,int r,int w){
  134. if(tl >= l && tr <= r){
  135. T[now].lazy += w; T[now].ff += w; T[now].R += w; T[now].REC+=w;
  136. return;
  137. }
  138. if(T[now].lazy) push_down(now);
  139. int mid = (tl+tr)/;
  140. if(mid >= l) ModifyF(now<<,tl,mid,l,r,w);
  141. if(mid+ <= r) ModifyF(now<<|,mid+,tr,l,r,w);
  142. T[now] = merge(T[now<<],T[now<<|]);
  143. }
  144.  
  145. void SingleModify(int now,int w){
  146. int hole = tail[top[now]];
  147. segmentTree fk = Querylen(,,n,ind[top[hole]],ind[hole]);
  148. AddG(,,n,ind[now],w); now=fa[top[now]];
  149. while(now){
  150. segmentTree rl = Querylen(,,n,ind[top[hole]],ind[hole]);
  151. Ans.Erase(fk.REC); Ans.push(rl.REC);
  152. Son[now].Erase(fk.L); Son[now].push(rl.L);
  153. hole = tail[top[now]]; fk = Querylen(,,n,ind[top[hole]],ind[hole]);
  154. ModifyG(,,n,ind[now]); now = fa[top[now]];
  155. }
  156. Ans.Erase(fk.REC);
  157. fk = Querylen(,,n,ind[top[hole]],ind[hole]);
  158. Ans.push(fk.REC);
  159. }
  160.  
  161. void WideModify(int now,int LCA,int w){
  162. while(dep[now] >= dep[LCA]){
  163. segmentTree fk = Querylen(,,n,ind[top[now]],ind[tail[top[now]]]);
  164. if(dep[top[now]] < dep[LCA]) ModifyF(,,n,ind[LCA],ind[now],w);
  165. else ModifyF(,,n,ind[top[now]],ind[now],w);
  166. Ans.Erase(fk.REC);
  167. fk = Querylen(,,n,ind[top[now]],ind[tail[top[now]]]);
  168. Ans.push(fk.REC);
  169. now = fa[top[now]];
  170. }
  171. }
  172.  
  173. void Modify(int u,int v,int w){
  174. int LCA = QueryLca(u,v);
  175. SingleModify(LCA,w);
  176. WideModify(u,LCA,w); // u
  177. WideModify(v,LCA,w); // v
  178. WideModify(LCA,LCA,-w); // LCA
  179. }
  180.  
  181. void build_tree(int now,int tl,int tr){
  182. if(tl == tr){
  183. tl = dr[tl];
  184. for(auto it : g[tl]){
  185. if(it == son[tl] || it == fa[tl]) continue;
  186. Son[tl].push();
  187. }
  188. }else{
  189. int mid = (tl+tr)/;
  190. build_tree(now<<,tl,mid); build_tree(now<<|,mid+,tr);
  191. }
  192. }
  193.  
  194. void work(){
  195. dfs1(,,);
  196. dfs2(,);
  197. build_tree(,,n);
  198. for(int i=;i<=m;i++){
  199. char ch = getchar(); while(ch != '+' && ch != '-') ch = getchar();
  200. int fr,t,w;
  201. if(ch == '+'){
  202. scanf("%d%d%d",&fr,&t,&w);Q[i].from=fr;Q[i].to=t;Q[i].w=w;
  203. }else{
  204. int x; scanf("%d",&x);fr = Q[x].from,t = Q[x].to,w = -Q[x].w;
  205. }
  206. Modify(fr,t,w);
  207. printf("%lld\n",Ans.top());
  208. }
  209. }
  210.  
  211. int main(){
  212. read();
  213. work();
  214. return ;
  215. }

UOJ268 [清华集训2016] 数据交互 【动态DP】【堆】【树链剖分】【线段树】的更多相关文章

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

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

  2. 【bzoj4712】洪水 树链剖分+线段树维护树形动态dp

    题目描述 给出一棵树,点有点权.多次增加某个点的点权,并在某一棵子树中询问:选出若干个节点,使得每个叶子节点到根节点的路径上至少有一个节点被选择,求选出的点的点权和的最小值. 输入 输入文件第一行包含 ...

  3. 洛谷P3313 [SDOI2014]旅行 题解 树链剖分+线段树动态开点

    题目链接:https://www.luogu.org/problem/P3313 这道题目就是树链剖分+线段树动态开点. 然后做这道题目之前我们先来看一道不考虑树链剖分之后完全相同的线段树动态开点的题 ...

  4. P3313 [SDOI2014]旅行——树链剖分+线段树(动态开点?)

    P3313 [SDOI2014]旅行 一棵树,其中的点分类,点有权值,在一条链上找到一类点中的最大值或总和: 树链剖分把树变成链: 把每个宗教单开一个线段树,维护区间总和和最大值: 宗教很多,需要动态 ...

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

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

  6. Tsinsen A1517. 动态树 树链剖分,线段树,子树操作

    题目 : http://www.tsinsen.com/A1517 A1517. 动态树 时间限制:3.0s   内存限制:1.0GB    总提交次数:227   AC次数:67   平均分:49. ...

  7. 【BZOJ-3589】动态树 树链剖分 + 线段树 + 线段覆盖(特殊的技巧)

    3589: 动态树 Time Limit: 30 Sec  Memory Limit: 1024 MBSubmit: 405  Solved: 137[Submit][Status][Discuss] ...

  8. Gym - 101848C Object-Oriented Programming (树链剖分+线段树+动态开点)

    C. Object-Oriented Programming time limit per test 3.0 s memory limit per test 1024 MB input standar ...

  9. BZOJ 3531 SDOI2014 旅行 树链剖分+线段树动态开点

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3531 题意概述: 给出一棵N个点的树,树上的每个结点有一个颜色和权值,支持以下四种操作: ...

随机推荐

  1. 两篇 Spring 总结(一)

    Spring4 概述以及 HelloWorld 概述 Spring 是一个 IOC(DI) 和 AOP 容器框架. 轻量级,Spring 是非侵入的,即使用的时候不需要实现任何接口或继承任何父类 面向 ...

  2. 助力ASP.NET Core 2.1开发!Layx 企业级弹窗插件发布!

    我们在开发B/S架构企业管理系统时经常用到弹窗.目前市场上主要有两大弹窗:layer/artdialog,这两款做的都非常的棒.由于我们ERP系统比较复杂.需要能够拥有和Windows弹窗一样的弹窗组 ...

  3. Jmeter(三十八)while控制器实现ssh三次重连

    在jmeter中,可以使用SSH协议连接主机进行相关操作, 步骤如下 首先添加一个ssh command  我们的测试交流群:317765580 在command中填写远程连接的必要信息 结果树中可以 ...

  4. python读取/创建XML文件

    Python中定义了很多处理XML的函数,如xml.dom,它会在处理文件之前,将根据xml文件构建的树状数据存在内存.还有xml.sax,它实现了SAX API,这个模块牺牲了便捷性,换取了速度和减 ...

  5. Python_每日习题_0003_完全平方数

    # 题目 一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少? # 程序分析 因为168对于指数爆炸来说实在太小了,所以可以直接省略数学分析,用最朴素的方法来获取 ...

  6. 三次握手复习TCP

    临近下班,突然想起三次握手的概念有点模糊. 大学时候的<计算机网络>是英语版的,那时候学习迷迷糊糊的.大概记得一个模型罢了. 幸好,大学基本所有的书都卖了,就是计算机网络没卖.待会回去看看 ...

  7. 福州大学软件工程1816 | W班 第10次作业[个人作业——软件产品案例分析]

    作业链接 个人作业--软件产品案例分析 评分细则 本次个人项目分数由两部分组成(课堂得分(老师/助教占比60%,学生占比40%)满分40分+博客分满分60分) 课堂得分和博客得分表 评分统计图 千帆竞 ...

  8. Linux 典型应用之服务管理

    crontab 定时任务 用户所建立的crontab文件中,每一行都代表一项任务,每行的每个字段代表一项设置,它的格式共分为六个字段,前五段是时间设定段,第六段是要执行的命令段,格式如下: minut ...

  9. [转帖]Ipvsadm参数详解(常用命令)

    Ipvsadm参数详解(常用命令) 2013年11月29日 12:41:40 怀素1980 阅读数:15901   版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.cs ...

  10. MySQL 单个表锁死 对查询语句无响应

    这个时候应该怀疑读取都被加锁,应该尝试使用 show processlist 查看每一个正在运行的进程. 可以看到这样一个列表,里面有使用者即用户,正在使用数据库的 host, 使用的 db 目前的 ...