首先O(n2)dp很好想

f[i][j]表示i子树内的所有边都被覆盖且i~j的路径也都被覆盖的最小花费。

考虑去掉无用的状态,其实真正用到的就是每一条链。

去掉第二维,f[i]表示i子树内的边都被覆盖且父向边也被覆盖的最小花费。

那么怎么转移呢?

f[i]可以是任意一条包含i和fa[i]的链转移而来,

首先要选这条链,还要加上这条链下端点到i所有其他儿子的f值,这样复杂度好像依旧很高

再优化,这不就是线段树取一个min吗?

那么我们现在要做的就是在每一个点上,在对应的一些链中取一个min

对于每条链,它是在它的下端点之上开始做出贡献的,

所以每个点控制的区间要是它的子树中所有向上连的边

当我们搞点x时,首先要算出他所有儿子的f值加和sum.然后要将以x为下端点的链的值更新为sum+c[i],还要将所有以x为上端点的链赋值inf,还要对其所有儿子的控制的链都加上sum-f[son],最后对于他控制的所有链取一个min就好了.

代码

 #include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define N 300005
#define inf 1000000000000000ll
#define LL long long
using namespace std;
int n,m,c[N];
int e=,head[N],out[N],in[N];
struct edge{int v,next;}ed[*N];
void add(int u,int v,int *h){
ed[e]=(edge){v,h[u]};
h[u]=e++;
}
int L[N],R[N],tot,d[N];
void dfs(int x,int fa){
L[x]=tot+;
for(int i=in[x];i;i=ed[i].next)
d[ed[i].v]=++tot;
for(int i=head[x];i;i=ed[i].next)
if(ed[i].v!=fa)dfs(ed[i].v,x);
R[x]=tot;
}
LL f[N];
LL minn[*N],lazy[*N];
void update(int rt,int l,int r,int x,LL y){
if(l==r){minn[rt]=y;return ;}
int mid=(l+r)>>;
if(x<=mid)update(rt<<,l,mid,x,y);
else update(rt<<|,mid+,r,x,y);
minn[rt]=min(min(minn[rt<<],minn[rt<<|])+lazy[rt],inf);
}
void add(int rt,int l,int r,int x,int y,LL z){
if(x<=l&&r<=y){lazy[rt]+=z;minn[rt]+=z;return ;}
int mid=(l+r)>>;
if(x<=mid) add(rt<<,l,mid,x,y,z);
if(y>mid) add(rt<<|,mid+,r,x,y,z);
minn[rt]=min(min(minn[rt<<],minn[rt<<|])+lazy[rt],inf);
}
LL query(int rt,int l,int r,int x,int y){
if(x<=l&&r<=y) return minn[rt];
LL ans=inf;
int mid=(l+r)>>;
if(x<=mid)ans=min(ans,query(rt<<,l,mid,x,y));
if(y>mid) ans=min(ans,query(rt<<|,mid+,r,x,y));
return min(ans+lazy[rt],inf);
}
void solve(int x,int fa){
LL ans=;
for(int i=head[x];i;i=ed[i].next){
if(ed[i].v==fa)continue;
solve(ed[i].v,x);
ans=min(f[ed[i].v]+ans,inf);
}
if(x==){f[]=ans;return;}
for(int i=in[x];i;i=ed[i].next)
update(,,m,d[ed[i].v],ans+c[ed[i].v]);
for(int i=out[x];i;i=ed[i].next)
update(,,m,d[ed[i].v],inf);
for(int i=head[x];i;i=ed[i].next){
if(ed[i].v==fa)continue;
add(,,m,L[ed[i].v],R[ed[i].v],ans-f[ed[i].v]);
}
f[x]=query(,,m,L[x],R[x]);
} int main(){
scanf("%d%d",&n,&m);
for(int i=,u,v;i<n;i++){
scanf("%d%d",&u,&v);
add(u,v,head);
add(v,u,head);
}
for(int i=,u,v;i<=m;i++){
scanf("%d%d%d",&u,&v,&c[i]);
add(u,i,in);
add(v,i,out);
}
dfs(,);
memset(minn,0x15f,sizeof minn);
memset(lazy,,sizeof lazy);
solve(,);
if(f[]>=inf)printf("-1\n");
else printf("%lld\n",f[]);
return ;
}

youmu

codeforces 671D的更多相关文章

  1. Codeforces 671D Roads in Yusland [树形DP,线段树合并]

    洛谷 Codeforces 这是一个非正解,被正解暴踩,但它还是过了. 思路 首先很容易想到DP. 设\(dp_{x,i}\)表示\(x\)子树全部被覆盖,而且向上恰好延伸到\(dep=i\)的位置, ...

  2. codeforces 671D Roads in Yusland & hdu 5293 Tree chain problem

    dp dp优化 dfs序 线段树 算是一个套路.可以处理在树上取链的问题.

  3. Codeforces 671D. Roads in Yusland(树形DP+线段树)

    调了半天居然还能是线段树写错了,药丸 这题大概是类似一个树形DP的东西.设$dp[i]$为修完i这棵子树的最小代价,假设当前点为$x$,但是转移的时候我们不知道子节点到底有没有一条越过$x$的路.如果 ...

  4. python爬虫学习(5) —— 扒一下codeforces题面

    上一次我们拿学校的URP做了个小小的demo.... 其实我们还可以把每个学生的证件照爬下来做成一个证件照校花校草评比 另外也可以写一个物理实验自动选课... 但是出于多种原因,,还是绕开这些敏感话题 ...

  5. 【Codeforces 738D】Sea Battle(贪心)

    http://codeforces.com/contest/738/problem/D Galya is playing one-dimensional Sea Battle on a 1 × n g ...

  6. 【Codeforces 738C】Road to Cinema

    http://codeforces.com/contest/738/problem/C Vasya is currently at a car rental service, and he wants ...

  7. 【Codeforces 738A】Interview with Oleg

    http://codeforces.com/contest/738/problem/A Polycarp has interviewed Oleg and has written the interv ...

  8. CodeForces - 662A Gambling Nim

    http://codeforces.com/problemset/problem/662/A 题目大意: 给定n(n <= 500000)张卡片,每张卡片的两个面都写有数字,每个面都有0.5的概 ...

  9. CodeForces - 274B Zero Tree

    http://codeforces.com/problemset/problem/274/B 题目大意: 给定你一颗树,每个点上有权值. 现在你每次取出这颗树的一颗子树(即点集和边集均是原图的子集的连 ...

随机推荐

  1. JVM学习--(七)性能监控工具

    前言 工欲善其事必先利其器,性能优化和故障排查在我们大都数人眼里是件比较棘手的事情,一是需要具备一定的原理知识作为基础,二是需要掌握排查问题和解决问题的流程.方法.本文就将介绍利用性能监控工具,帮助开 ...

  2. MQ队列管理器搭建(三)

    MQ集群及网关队列管理器的搭建 描述:     如上图所示,为MQ的集群搭建部署图.CLUSTERA.CLUSTERB分别是两个集群,其中Qm1-Qm3.GateWayA为CLUSTERA集群中的队列 ...

  3. 别跟我谈EF抵抗并发,敢问你到底会不会用EntityFramework

    前言 一直以来写的博文都是比较温婉型的博文,今天这篇博文算是一篇批判性博文,有问题欢迎探讨,如标题,你到底会不会用EntityFramework啊. 你到底会不会用EntityFramework啊 面 ...

  4. Java的运行原理

    在Java中引入了虚拟机的概念,即在机器和编译程序之间加入了一层抽象的虚拟的机器.这台虚拟的机器在任何平台上都提供给编译程序一个的共同的接口.编译程序只需要面向虚拟机,生成虚拟机能够理解的代码,然后由 ...

  5. java并发包小结(一)

    java.util.concurrent 包含许多线程安全.高性能的并发构建块.换句话讲,创建 java.util.concurrent 的目的就是要实现 Collection 框架对数据结构所执行的 ...

  6. STL容器的基本特性和特征

    1. STL有6种序列容器类型(1)vector它提供对元素的随即访问,在尾部添加和删除元素的时间是固定的,在头部或中部插入和删除元素的复杂度为线性时间.(2)deque在文件中声明.是双端队列,支持 ...

  7. MySql 动态语句

    MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) ...

  8. Hystrix 熔断机制原理

    相关配置 circuitBreaker.enabled 是否开启熔断 circuitBreaker.requestVolumeThreshold 熔断最低触发请求数阈值 circuitBreaker. ...

  9. JavaScript中push ,pop ,concat ,join方法

    push 方法 将新元素添加到一个数组中,并返回数组的新长度值. arrayObj.push([item1 [item2[. . . [itemN ]]]]) 说明 push 方法将以新元素出现的顺序 ...

  10. dw cs6 trial

    试用版: https://helpx.adobe.com/x-productkb/policy-pricing/cs6-product-downloads.html English/Japanese: ...