题目分析:

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

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

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

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

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

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

考虑合并。

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

代码:

 #include<bits/stdc++.h>
using namespace std; typedef long long ll; const int maxn = ; int n,m; vector <int> g[maxn];
int sz[maxn],top[maxn],fa[maxn],dep[maxn],son[maxn],ind[maxn],dr[maxn];
int tail[maxn],num; struct Query{int from,to,w;}Q[maxn];
struct Priority_Queue{
priority_queue<ll,vector<ll>,less<ll> > pq,del;
void push(ll now){pq.push(now);}
void pop(){
while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop();
pq.pop();
}
ll top(){
while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop();
if(pq.empty()) return ;
else return pq.top();
}
ll sec(){
while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop();
if(pq.size() ==) return ;
ll oop = pq.top(); pq.pop();
while(!del.empty() && pq.top() == del.top()) pq.pop(),del.pop();
if(pq.size() == ){pq.push(oop);return ;}
else {ll ret = pq.top();pq.push(oop);return ret;}
}
void Erase(ll now){del.push(now);}
}Son[maxn],Ans; struct segmentTree{
ll tg,ff,lazy,REC,L,R;
}T[maxn<<]; void push_down(int now){
T[now<<].ff += T[now].lazy; T[now<<|].ff += T[now].lazy;
T[now<<].REC += T[now].lazy; T[now<<|].REC += T[now].lazy;
T[now<<].lazy += T[now].lazy; T[now<<|].lazy += T[now].lazy;
T[now<<].R += T[now].lazy; T[now<<|].R += T[now].lazy;
T[now].lazy = ;
} segmentTree merge(segmentTree alpha,segmentTree beta){
segmentTree RES;RES.lazy = ; RES.ff = ;
RES.tg = alpha.tg + beta.tg;
RES.REC = max(alpha.REC,beta.REC);
RES.REC = max(RES.REC,alpha.R + beta.L);
RES.L = max(alpha.L,alpha.tg + beta.L);
RES.R = max(beta.R,alpha.R + beta.tg);
return RES;
} void dfs1(int now,int f,int dp){
dep[now] = dp; fa[now] = f;
int maxx = ;
for(auto it:g[now]){
if(it == f) continue;
dfs1(it,now,dp+);
sz[now] += sz[it];
if(maxx == || sz[it] > sz[maxx]) maxx = it;
}
son[now] = maxx; sz[now]++;
} void dfs2(int now,int tp){
top[now] = tp; ind[now] = ++num; dr[num] = now;
if(now == tp) Ans.push();
if(son[now]) dfs2(son[now],tp);
else tail[tp] = now;
for(auto it : g[now]){
if(it == fa[now] || it == son[now]) continue;
dfs2(it,it);
}
} void read(){
scanf("%d%d",&n,&m);
for(int i=;i<n;i++){
int u,v; scanf("%d%d",&u,&v);
g[u].push_back(v); g[v].push_back(u);
}
} int QueryLca(int u,int v){
while(top[u] != top[v]){
if(dep[top[u]] > dep[top[v]]) u = fa[top[u]];
else v = fa[top[v]];
}
if(dep[u] < dep[v]) return u; else return v;
} segmentTree Querylen(int now,int tl,int tr,int l,int r){
if(tl >= l && tr <= r) return T[now];
if(T[now].lazy) push_down(now);
int mid = (tl+tr)/;
if(mid < l) return Querylen(now<<|,mid+,tr,l,r);
if(mid >= r) return Querylen(now<<,tl,mid,l,r);
segmentTree pp = Querylen(now<<|,mid+,tr,l,r);
segmentTree qq = Querylen(now<<,tl,mid,l,r);
return merge(qq,pp);
} void AddG(int now,int tl,int tr,int place,int w){
if(tl == tr){T[now].tg += w;T[now].L += w;return;}
if(T[now].lazy) push_down(now);
int mid = (tl+tr)/;
if(mid >= place) AddG(now<<,tl,mid,place,w);
else AddG(now<<|,mid+,tr,place,w);
T[now] = merge(T[now<<],T[now<<|]);
} void ModifyG(int now,int tl,int tr,int place){
if(tl == tr){
tl = dr[tl]; T[now].L = Son[tl].top() + T[now].tg;
T[now].REC = T[now].ff + Son[tl].top() + Son[tl].sec();
T[now].R = T[now].ff + Son[tl].top();
return;
}
if(T[now].lazy) push_down(now);
int mid = (tl+tr)/;
if(mid >= place) ModifyG(now<<,tl,mid,place);
else ModifyG(now<<|,mid+,tr,place);
T[now] = merge(T[now<<],T[now<<|]);
} void ModifyF(int now,int tl,int tr,int l,int r,int w){
if(tl >= l && tr <= r){
T[now].lazy += w; T[now].ff += w; T[now].R += w; T[now].REC+=w;
return;
}
if(T[now].lazy) push_down(now);
int mid = (tl+tr)/;
if(mid >= l) ModifyF(now<<,tl,mid,l,r,w);
if(mid+ <= r) ModifyF(now<<|,mid+,tr,l,r,w);
T[now] = merge(T[now<<],T[now<<|]);
} void SingleModify(int now,int w){
int hole = tail[top[now]];
segmentTree fk = Querylen(,,n,ind[top[hole]],ind[hole]);
AddG(,,n,ind[now],w); now=fa[top[now]];
while(now){
segmentTree rl = Querylen(,,n,ind[top[hole]],ind[hole]);
Ans.Erase(fk.REC); Ans.push(rl.REC);
Son[now].Erase(fk.L); Son[now].push(rl.L);
hole = tail[top[now]]; fk = Querylen(,,n,ind[top[hole]],ind[hole]);
ModifyG(,,n,ind[now]); now = fa[top[now]];
}
Ans.Erase(fk.REC);
fk = Querylen(,,n,ind[top[hole]],ind[hole]);
Ans.push(fk.REC);
} void WideModify(int now,int LCA,int w){
while(dep[now] >= dep[LCA]){
segmentTree fk = Querylen(,,n,ind[top[now]],ind[tail[top[now]]]);
if(dep[top[now]] < dep[LCA]) ModifyF(,,n,ind[LCA],ind[now],w);
else ModifyF(,,n,ind[top[now]],ind[now],w);
Ans.Erase(fk.REC);
fk = Querylen(,,n,ind[top[now]],ind[tail[top[now]]]);
Ans.push(fk.REC);
now = fa[top[now]];
}
} void Modify(int u,int v,int w){
int LCA = QueryLca(u,v);
SingleModify(LCA,w);
WideModify(u,LCA,w); // u
WideModify(v,LCA,w); // v
WideModify(LCA,LCA,-w); // LCA
} void build_tree(int now,int tl,int tr){
if(tl == tr){
tl = dr[tl];
for(auto it : g[tl]){
if(it == son[tl] || it == fa[tl]) continue;
Son[tl].push();
}
}else{
int mid = (tl+tr)/;
build_tree(now<<,tl,mid); build_tree(now<<|,mid+,tr);
}
} void work(){
dfs1(,,);
dfs2(,);
build_tree(,,n);
for(int i=;i<=m;i++){
char ch = getchar(); while(ch != '+' && ch != '-') ch = getchar();
int fr,t,w;
if(ch == '+'){
scanf("%d%d%d",&fr,&t,&w);Q[i].from=fr;Q[i].to=t;Q[i].w=w;
}else{
int x; scanf("%d",&x);fr = Q[x].from,t = Q[x].to,w = -Q[x].w;
}
Modify(fr,t,w);
printf("%lld\n",Ans.top());
}
} int main(){
read();
work();
return ;
}

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. python第七章:常用模块--小白博客

    yagmail模块 python标准库中发送电子邮件的模块比较复杂,因此,有许多开原的库提供了更加易用的接口来发送电子邮件,其中yagmail是一个使用比较广泛的开原项目,yagmail底层依然使用了 ...

  2. Atcoder F - LCS (DP-最长公共子序列,输出字符串)

    F - LCS Time Limit: 2 sec / Memory Limit: 1024 MB Score : 100100 points Problem Statement You are gi ...

  3. 小小知识点(二)——如何修改win10 的C盘中用户下的文件夹名称

    1.以管理员身份登录计算机 在win10桌面的开始界面处有个用户头像,点击在里面找到administrator: 如果没有,则需进行如下设置: (1)右键计算机,双击管理,找到如下所示的用户中的adm ...

  4. form-data、x-www-form-urlencoded的区别

    form-data可以上传文件格式的,比如mp3.jpg这些:x-www-form-urlencoded不能选择格式文件,只能传key-value这种string格式的内容.

  5. rest framwork 小试身手

    models.py from django.db import models class Course(models.Model): """ 课程表 "&quo ...

  6. Oracle如何扩展表空间

    一: --查看表空间的名字及文件所在位置 select tablespace_name, file_id, file_name, ), ) total_space from sys.dba_data_ ...

  7. React Native之图片保存到本地相册(ios android)

    React Native之图片保存到本地相册(ios android) 一,需求分析 1,react native保存网络图片到相册,iOS端可以用RN自带的CameraRoll完美解决,但是andr ...

  8. Oracle 用户管理与权限分配

    用户管理是系统管理员最基本的任务之一,用户想要连接数据库并且使用相应的系统资源就必须是系统的合法用户且具有对应的权限. 1 创建用户 default tablespace default_tables ...

  9. Mybatis测试用例

    package cn.zhangxueliang.mybatis.mapper; import static org.junit.Assert.*; import java.io.InputStrea ...

  10. spring bean之间的关系:继承,依赖,注入

    一 继承 spring中多个bean之间的继承关系,和面向对象中的继承关系类似,直接看代码. 先定义一个Person类 package com.demo.spring.entity; /** * @a ...