n<=300000个点的树,给m<=300000条带权路径(ui,vi,保证vi是ui的祖先)求覆盖整棵树每条边的最小权和。

好题好姿势!直观的看到可以树形DP,f[i]表示把点i包括它爸爸下面那条边都覆盖的最小权,就用经过他爸爸那条边的所有路径,各条路径加上一些子树信息来更新即可。

这样时间炸,那看看怎么优化。实际上我们不是在单纯地用一条路径更新答案,而是这样一个东西:

其中红色那条是题目给的路径,实际上是加上蓝色边连接的点的f[i]来更新边2上端的那个点的答案的。也就是说,一条路径来更新答案,要在这条路径的尾部加上那些点权(1),然后在更新某个点的答案的时候加上这个点下面的这条路径的分叉(2)。而更新一个点的路径,其实都是这个点对应子树的路径。至于子树中那些够不到这个点的路径,只需在扫到头的时候把这条路径的答案变inf即可。

为了实现这个操作,即找到“起点在子树里的所有路径的答案”,我们用dfs序给每个路径的起点(下端点)编号,再dfs求每个点的答案;每次求答案时,先把以该点为起点的新路径赋初值,即该点所有子树的f[j]和,并把终点在该点的路径答案置inf;然后给经过该点的路径加“分叉”;由于dfs序编号好了,能更新这个节点的路径(上面提到的起点在这个子树内的路径)是连续的一个区间,因此用个线段树维护区间min即可。

至于加“分叉”,观察可以发现:假如经过i的某路径来自子树j,那么应该把它答案加上点i其他儿子的f和。所以在加“分叉”时只需要再枚举一次孩子,把孩子子树内所有的路径加上其他孩子的f[j]和即可。

废话少说见代码!

 #include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
//#include<iostream>
using namespace std; int n,m;
#define maxn 300011
struct Edge{int to,next;}edge[maxn*];int first[maxn],start[maxn],end[maxn],le=;
void in(int x,int y,int* first) {edge[le].to=y;edge[le].next=first[x];first[x]=le++;}
void insert(int x,int y,int* first) {in(x,y,first);in(y,x,first);}
int dfn[maxn],Left[maxn],Right[maxn],Time=;
void dfs(int x,int fa)
{
Left[x]=Time+;
for (int i=start[x];i;i=edge[i].next)
{
Edge &e=edge[i];
dfn[e.to]=++Time;
}
for (int i=first[x];i;i=edge[i].next)
{
Edge &e=edge[i];
if (e.to!=fa) dfs(e.to,x);
}
Right[x]=Time;
}
#define LL long long
LL val[maxn];
const LL inf=1e15+;
struct SMT
{
struct Node
{
LL Min;
LL add;
int l,r;
int ls,rs;
}a[maxn*];
int size;
SMT() {size=;}
void build(int &x,int L,int R)
{
x=++size;
a[x].Min=inf;a[x].add=;
a[x].l=L;a[x].r=R;
if (L==R) {a[x].ls=a[x].rs=;}
else
{
const int mid=(L+R)>>;
build(a[x].ls,L,mid);
build(a[x].rs,mid+,R);
}
}
void build() {int x;build(x,,m);}
void up(int x)
{
const int &p=a[x].ls,&q=a[x].rs;
a[x].Min=min(a[p].Min,a[q].Min);
}
void addsingle(int x,LL v)
{
a[x].Min+=v;
a[x].Min=min(inf,a[x].Min);
a[x].add+=v;
}
void down(int x)
{
const int &p=a[x].ls,&q=a[x].rs;
if (a[x].add)
{
addsingle(p,a[x].add);
addsingle(q,a[x].add);
a[x].add=;
}
}
int ql,qr;LL v;
void be(int x)
{
if (a[x].l==a[x].r) {a[x].Min=v;return;}
down(x);
const int mid=(a[x].l+a[x].r)>>;
if (ql<=mid) be(a[x].ls);
if (ql> mid) be(a[x].rs);
up(x);
}
void be(int p,LL v) {ql=qr=p;this->v=v;be();}
void Add(int x)
{
if (ql<=a[x].l && a[x].r<=qr) {addsingle(x,v);return;}
down(x);
const int mid=(a[x].l+a[x].r)>>;
if (ql<=mid) Add(a[x].ls);
if (qr> mid) Add(a[x].rs);
up(x);
}
void Add(int L,int R,LL v) {if (L>R) return;ql=L;qr=R;this->v=v;Add();}
LL query(int x)
{
if (ql<=a[x].l && a[x].r<=qr) return a[x].Min;
down(x);
const int mid=(a[x].l+a[x].r)>>;LL ans=inf;
if (ql<=mid) ans=min(ans,query(a[x].ls));
if (qr> mid) ans=min(ans,query(a[x].rs));
return ans;
}
LL query(int L,int R) {if (L>R) return inf;ql=L;qr=R;return query();}
}t;
LL f[maxn];
void play(int x,int fa)
{
LL tot=;
for (int i=first[x];i;i=edge[i].next)
{
Edge &e=edge[i];if (e.to==fa) continue;
play(e.to,x);
tot=min(inf,f[e.to]+tot);
}
for (int i=start[x];i;i=edge[i].next)
{
Edge &e=edge[i];
t.be(dfn[e.to],tot+val[e.to]);
}
for (int i=end[x];i;i=edge[i].next)
{
Edge &e=edge[i];
t.be(dfn[e.to],inf);
}
if (x==) f[]=tot;
else if (tot<inf)
{
for (int i=first[x];i;i=edge[i].next)
{
Edge &e=edge[i];if (e.to==fa) continue;
t.Add(Left[e.to],Right[e.to],tot-f[e.to]);
}
f[x]=t.query(Left[x],Right[x]);
}
else f[x]=inf;
}
void play()
{
dfs(,);
t.build();
play(,);
}
int x,y;LL v;
int main()
{
scanf("%d%d",&n,&m);
for (int i=;i<n;i++)
{
scanf("%d%d",&x,&y);
insert(x,y,first);
}
for (int i=;i<=m;i++)
{
scanf("%d%d%I64d",&x,&y,&val[i]);
in(x,i,start);
in(y,i,end);
}
play();
printf(f[]>=inf?"-1\n":"%I64d\n",f[]);
return ;
}

还有一种贪心写法哦!

CF671D:Roads in Yusland的更多相关文章

  1. 【CF671D】Roads in Yusland(贪心,左偏树)

    [CF671D]Roads in Yusland(贪心,左偏树) 题面 洛谷 CF 题解 无解的情况随便怎么搞搞提前处理掉. 通过严密(大雾)地推导后,发现问题可以转化成这个问题: 给定一棵树,每条边 ...

  2. 【CF671D】 Roads in Yusland(对偶问题,左偏树)

    传送门 洛谷翻译 CodeForces Solution emmm,先引入一个对偶问题的概念 \(max(c^Tx|Ax \leq b)=min(b^Ty|A^Ty \ge c)\) 考虑这个式子的现 ...

  3. Codeforces 671 D. Roads in Yusland

    题目描述 Mayor of Yusland just won the lottery and decided to spent money on something good for town. Fo ...

  4. [Codeforces671D]Roads in Yusland

    [Codeforces671D]Roads in Yusland Tags:题解 题意 luogu 给定以1为根的一棵树,有\(m\)条直上直下的有代价的链,求选一些链把所有边覆盖的最小代价.若无解输 ...

  5. 【CF617D】Roads in Yusland

    [CF617D]Roads in Yusland 题面 蒯的洛谷的 题解 我们现在已经转化好了题目了,戳这里 那么我们考虑怎么求这个东西,我们先判断一下是否所有的边都能被覆盖,不行的话输出\(-1\) ...

  6. 【CodeForces】671 D. Roads in Yusland

    [题目]D. Roads in Yusland [题意]给定n个点的树,m条从下往上的链,每条链代价ci,求最少代价使得链覆盖所有边.n,m<=3*10^5,ci<=10^9,time=4 ...

  7. codesforces 671D Roads in Yusland

    Mayor of Yusland just won the lottery and decided to spent money on something good for town. For exa ...

  8. CF671D Roads in Yusland

    一道很玄妙的题= = 我们考虑先考虑DP 那么有$f[x]=min(c+\sum f[y])$ $f[x]$表示覆盖x的子树和x->fa[x]的所有边最小代价 我们枚举一条边c覆盖的x-> ...

  9. 题解-Codeforces671D Roads in Yusland

    Problem Codeforces-671D 题意概要:给定一棵 \(n\) 点有根树与 \(m\) 条链,链有费用,保证链端点之间为祖先关系,问至少花费多少费用才能覆盖整棵树(\(n-1\) 条边 ...

随机推荐

  1. 微信小程序开发系列五:微信小程序中如何响应用户输入事件

    微信小程序开发系列教程 微信小程序开发系列一:微信小程序的申请和开发环境的搭建 微信小程序开发系列二:微信小程序的视图设计 微信小程序开发系列三:微信小程序的调试方法 微信小程序开发系列四:微信小程序 ...

  2. Python3基础教程(十六)—— 迭代器、生成器、装饰器

    在这个实验里我们学习迭代器.生成器.装饰器有关知识. 这几个概念是 Python 中不容易理解透彻的概念,务必把所有的实验代码都完整的输入并理解清楚其中每一行的意思. 迭代器 Python 迭代器(I ...

  3. iview table 普通表格样式

    iview table 普通表格样式 https://run.iviewui.com/UvLFPMb0 <template> <table> <thead> < ...

  4. k8s集群之master节点部署

    apiserver的部署 api-server的部署脚本 [root@mast-1 k8s]# cat apiserver.sh #!/bin/bash MASTER_ADDRESS=$1 主节点IP ...

  5. Java文件编译与反编译:javac命令和javap命令

    1.创建一个Test.java文件,并输入内容 public class Test{ private int m; public int inc(){ return m + 1; } } 2.使用ja ...

  6. echart-柱状图

    目前在改别人遗留的bug,需求: 宽度 自适应的情况下 展示不友好:宽度太大 上下不居中 需求 要 上下 无论是否 有内容 都要居中展示 以0刻度为标准 宽度 设置 series: [ { name: ...

  7. Eaton Char-Lynn Motor : Performance Of Small Displacement Motors

    The small-displacement supercharged motor replaces the large-displacement motor with the speed of li ...

  8. jQuery判断一个元素是否为另一个元素的子元素(或者其本身)

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head& ...

  9. 如何学好C++语言(转)

    不久前发现陈皓的blog -- 酷壳,闲暇之余看看,学到不少东西,感觉作为一个程序员自己才刚开始也还有很长的路需要去走.真后悔本科到研究生的6年间看书不够,那只有从现在起不断的学习.最近有李开复老师得 ...

  10. python基础知识03-格式化输出和深浅复制

    VIM中HJKL可以上下左右移动光标. 格式化输出和深浅复制 1.字符串的拼接和格式化 sudo pip3 install ipython 安装 ipython 进入 字符串相加 str1 + str ...