题意

给出 \(n\) 个点的树,每个时刻可能出现一条路径 \(A_i\) 或者之前出现的某条路径 \(A_i\) 消失,每条路径有一个权值,求出在每个时刻过后能够找到的权值最大的路径(指所有和该路径有交的路径 \(A\) 的权值和) \(B\) 的权值是多少。

\(n\leq 10^5\)

分析

结论:两条树上路径有交,则一定有一条路径经过另一条路径的 \(lca\).

  • 根据上面的性质我们考虑用树形dp的方式求解。

  • 将一条路径的权值在每个点 \(x\) 关系分成两种:

    • \(a\) :路径的 \(lca\) 是 \(x\) ;
    • \(b\) :路径的 \(lca\) 是 \(x\) 的祖先;
  • 假设现在已经选定了一条路径 \(B\),那么该路径的权值就是途径所有点的 \(a\) 和 \(lca\) 的 \(b\) 之和 .

  • 考虑动态dp,因为树剖之后答案一定可以写成一段轻链+一段重链+一段轻链的形式。

  • 然后全局再用一个可删堆维护每条重链的答案即可。

  • 总时间复杂度为 \(O(nlog^2n)\)。

注意可删堆取次大值时要两次检查堆顶是否要被删除

代码

#include<bits/stdc++.h>
using namespace std;
#define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].lst,v=e[i].to)
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
typedef long long LL;
inline int gi(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
return x*f;
}
template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;}
template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;}
const int N=1e5 + 7,Nd=N<<2;
int n,m,edc;
int head[N],x[N],y[N],w[N];
struct edge{
int lst,to;
edge(){}edge(int lst,int to):lst(lst),to(to){}
}e[N*2];
void Add(int a,int b){
e[++edc]=edge(head[a],b),head[a]=edc;
e[++edc]=edge(head[b],a),head[b]=edc;
}
// slpf
int son[N],zson[N],fa[N],dep[N],in[N],top[N],rev[N],down[N],tim;
void dfs1(int u){
son[u]=1;
go(u)if(v^fa[u]){
fa[v]=u,dep[v]=dep[u]+1,dfs1(v);
son[u]+=son[v];
if(son[v]>son[zson[u]]) zson[u]=v;
}
}
void dfs2(int u,int from){
top[u]=from,in[u]=++tim,rev[tim]=u,down[u]=u;
if(zson[u]) dfs2(zson[u],from),down[u]=down[zson[u]];
go(u)if(v^fa[u]&&v^zson[u]) dfs2(v,v);
}
int Lca(int x,int y){
for(;top[x]^top[y];y=fa[top[y]])
if(dep[top[x]]>dep[top[y]]) swap(x,y);
return dep[x]<dep[y]?x:y;
}
//sgt
#define Ls o<<1
#define Rs o<<1|1
struct data{
LL l,r,s,mx;
data(){}
data operator +(const data &rhs)const{
data res;
res.l=max(l,s+rhs.l);
res.r=max(rhs.r,rhs.s+r);
res.s=s+rhs.s;
res.mx=max(max(mx,rhs.mx),r+rhs.l);
return res;
}
}t[N<<2];
char s[10];
LL addv[Nd],g[Nd],se[Nd];
void st1(int o,LL v){
t[o].r+=v,t[o].mx+=v;
addv[o]+=v;
}
void pushup(int o){
t[o]=t[Ls]+t[Rs];
}
void pushdown(int o){
if(!addv[o]) return;
st1(Ls,addv[o]);
st1(Rs,addv[o]);
addv[o]=0;
}
void ma(int p,int l,int r,int o,int opt,LL v){
if(l==r){
if(!opt){
t[o].l+=v,t[o].r+=v,t[o].s+=v,t[o].mx+=v;
}else if(opt==1){
LL x=v-g[o];g[o]=v;
t[o].l+=x,t[o].r+=x,t[o].mx+=x;
}else{
LL x=v-se[o];se[o]=v;
t[o].mx+=x;
}
return;
}
pushdown(o);int mid=l+r>>1;
if(p<=mid) ma(p,l,mid,Ls,opt,v);
else ma(p,mid+1,r,Rs,opt,v);
pushup(o);
}
void mb(int L,int R,int l,int r,int o,LL v){
if(L>R) return;
if(L<=l&&r<=R){
st1(o,v);
return;
}
pushdown(o);int mid=l+r>>1;
if(L<=mid) mb(L,R,l,mid,Ls,v);
if(R>mid) mb(L,R,mid+1,r,Rs,v);
pushup(o);
}
data query(int L,int R,int l,int r,int o){
if(L<=l&&r<=R) return t[o];
pushdown(o);int mid=l+r>>1;
if(R<=mid) return query(L,R,l,mid,Ls);
if(L>mid) return query(L,R,mid+1,r,Rs);
return query(L,R,l,mid,Ls)+query(L,R,mid+1,r,Rs);
}
struct Heap{
priority_queue<LL>A,B;
void push(LL x){A.push(x);}
void pop(LL x){B.push(x);}
LL top(){
while(!B.empty()&&A.top()==B.top()) A.pop(),B.pop();
return A.empty()?0:A.top();
}
LL se(){
while(!B.empty()&&A.top()==B.top()) A.pop(),B.pop();
if(A.empty()) return -1;
LL x=A.top();A.pop();
while(!B.empty()&&A.top()==B.top()) A.pop(),B.pop();
if(B.empty()) {A.push(x);return -1;}
LL y=A.top();A.push(x);
return y;
}
}h[N],ans;
LL tans[N];
void upd(int u,int lca,LL v){
int x=u;
for(;u;u=fa[top[u]]){
int gg=fa[top[u]]; data res=query(in[top[u]],in[down[u]],1,n,1);
h[gg].pop(res.l);
if(tans[top[u]]) ans.pop(tans[top[u]]); if(u==x&&!lca) ma(in[u],1,n,1,0,v);
else{
if(lca) mb(max(in[top[u]],in[lca]+1),in[u],1,n,1,v);
ma(in[u],1,n,1,1,h[u].top());
} if(h[u].se()!=-1) ma(in[u],1,n,1,2,h[u].se());
res=query(in[top[u]],in[down[u]],1,n,1);
h[gg].push(res.l);
ans.push(tans[top[u]]=res.mx);
}
}
void pre(int u){
go(u)if(v^fa[u]) pre(v);
h[fa[top[u]]].push(0),ans.push(0);
}
int main(){
n=gi(),m=gi();
rep(i,1,n-1) Add(gi(),gi());
dep[1]=1,dfs1(1),dfs2(1,1);
pre(1);
rep(i,1,m){
scanf("%s",s);
if(s[0]=='+'){
x[i]=gi(),y[i]=gi(),w[i]=gi();
int lca=Lca(x[i],y[i]);
upd(lca,0,w[i]);
upd(x[i],lca,w[i]);
upd(y[i],lca,w[i]);
}else{
int t=gi(),lca=Lca(x[t],y[t]);
upd(lca,0,-w[t]);
upd(x[t],lca,-w[t]);
upd(y[t],lca,-w[t]);
}
printf("%lld\n",ans.top());
}
return 0;
}

[UOJ#268]. 【清华集训2016】数据交互[动态dp+可删堆维护最长链]的更多相关文章

  1. BZOJ 4732 UOJ #268 [清华集训2016]数据交互 (树链剖分、线段树)

    题目链接 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=4732 (UOJ) http://uoj.ac/problem/268 题解 ...

  2. UOJ268 [清华集训2016] 数据交互 【动态DP】【堆】【树链剖分】【线段树】

    题目分析: 不难发现可以用动态DP做. 题目相当于是要我求一条路径,所有与路径有交的链的代价加入进去,要求代价最大. 我们把链的代价分成两个部分:一部分将代价加入$LCA$之中,用$g$数组保存:另一 ...

  3. BZOJ4732. [清华集训2016]数据交互(树链剖分+线段树+multiset)

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=4732 题解 首先,一个比较显然的结论是:对于一棵有根树上的两条链 \((x_1, y_1 ...

  4. [UOJ#274][清华集训2016]温暖会指引我们前行

    [UOJ#274][清华集训2016]温暖会指引我们前行 试题描述 寒冬又一次肆虐了北国大地 无情的北风穿透了人们御寒的衣物 可怜虫们在冬夜中发出无助的哀嚎 “冻死宝宝了!” 这时 远处的天边出现了一 ...

  5. Uoj #274. 【清华集训2016】温暖会指引我们前行 LCT维护边权_动态最小生成树

    Code: 行#include<bits/stdc++.h> #define ll long long #define maxn 1000000 #define inf 100000000 ...

  6. [UOJ#276][清华集训2016]汽水[分数规划+点分治]

    题意 给定一棵 \(n\) 个点的树,给定 \(k\) ,求 \(|\frac{\sum w(路径长度)}{t(路径边数)}-k|\)的最小值. \(n\leq 5\times 10^5,k\leq ...

  7. [UOJ#276]【清华集训2016】汽水

    [UOJ#276][清华集训2016]汽水 试题描述 牛牛来到了一个盛产汽水的国度旅行. 这个国度的地图上有 \(n\) 个城市,这些城市之间用 \(n−1\) 条道路连接,任意两个城市之间,都存在一 ...

  8. UOJ 275. 【清华集训2016】组合数问题

    UOJ 275. [清华集训2016]组合数问题 组合数 $C_n^m $表示的是从 \(n\) 个物品中选出 \(m\) 个物品的方案数.举个例子,从$ (1,2,3)(1,2,3)$ 三个物品中选 ...

  9. UOJ #269. 【清华集训2016】如何优雅地求和

    UOJ #269. [清华集训2016]如何优雅地求和 题目链接 给定一个\(m\)次多项式\(f(x)\)的\(m+1\)个点值:\(f(0)\)到\(f(m)\). 然后求: \[ Q(f,n,x ...

随机推荐

  1. MySQL索引选择不正确并详细解析OPTIMIZER_TRACE格式

    一 表结构如下: CREATE TABLE t_audit_operate_log (  Fid bigint(16) AUTO_INCREMENT,  Fcreate_time int(10) un ...

  2. 参数innodb_force_recovery影响了整个InnoDB存储引擎的恢复状况

    参数innodb_force_recovery影响了整个InnoDB存储引擎的恢复状况.该值默认为0,表示当需要恢复时执行所有的恢复操作.当不能进行有效恢复时,如数据页发生了corruption,My ...

  3. MySQL crash-safe replication(2):

    MySQL数据库的成功离不开其replicaiton(复制),相对于Oracle DG和Microsoft SQL Server Log Shipping来说,其简单易上手,基本上1,2分钟内根据手册 ...

  4. C#读取AD域用户信息

    private const string domainName = "本机IP地址或域名"; private const string adAdmin = "管理员帐号& ...

  5. kettle性能优化

    普通开发电脑,如果没有网络查询步骤,kettle正常的速度应该在3000~20000条/秒.如果速度在2000条/秒一下,就可能需要调优. 性能优化的方式包括如下几种: 1.通过改变开始复制的数量(针 ...

  6. yum安装某个包出现冲突的情况

    yum安装是非常方便的,可以自动解决依赖问题,但是有时候我们安装包会出现冲突,这个时候我们就要查找是哪些包与哪些包出现冲突,然后再针对性的解决问题. 一般来说起冲突的包会报出来,主要为两点 1.包与包 ...

  7. python3: 数字日期和时间(1)

    ---恢复内容开始--- 1. 数字的四舍五入 Q: 你想对浮点数执行指定精度的舍入运算 A: 简单的使用内置的round(value, ndigits)函数即可. >>> roun ...

  8. .Net使用163smtp发送邮件时错误:邮箱不可用. has no permission解决方法

    C#实现简单邮件发送代码如下 public static void SendAsync(string emailTo, string subject, string mailBody) { var m ...

  9. 4.Dubbo2.5.3集群容错和负载均衡

    转载请出自出处:http://www.cnblogs.com/hd3013779515/ 1.集群容错和负载均衡原理 各节点关系: 这里的Invoker是Provider的一个可调用Service的抽 ...

  10. openlayers5实战--踩坑总结

    1.接口返回圆心坐标和半径,直接通过new Circle(center,radius)添加圆形feature变小问题. 解决办法: new  Feature()的geometry参数不能直接赋值new ...