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. (一)Mybatis之初步接触

    Maven的安装及环境配置 安装及配置只需按照以下三个链接的步骤走 撸帝的博客https://www.funtl.com/zh/maven/Maven-%E5%AE%89%E8%A3%85%E9%85 ...

  2. 【学习笔记】深入理解js原型和闭包(1)—— 一切都是对象

    “一切都是对象”这句话的重点在于如何去理解“对象”这个概念. ——当然,也不是所有的都是对象,值类型就不是对象. 首先咱们还是先看看javascript中一个常用的运算符——typeof.typeof ...

  3. eclipse搭建android开发环境详细步骤

    搭建android应用的开发环境,一套程序下来也是相当繁琐的,这里我整理下一整套详细流程: 1,下载JDK 去oracle官网下载最新版本的jdk,官网地址 http://www.oracle.com ...

  4. ZigBee cc2530芯片学习 error记录(1)

    ZigBee cc2530芯片学习 error记录   Error[e46]: Undefined external "LcdInit" referred in main( xxx ...

  5. TFS2010单独安装配置tfs build server

    记录一下确实很磨人. 同样硬件和软件环境的两台服务器,其中一台服务器很久之前就配置好了tfs2010 build ,然后最近想再配置一台tfs build server,但是按照以前的配置流程始终提示 ...

  6. 【算法】最长回文子串 longest palindrome substring

    对于字符串S, 要找到它最长的回文子串,能想到的最暴力方法,应该是对于每个元素i-th都向左向右对称搜索,最后用一个数组span 记录下相对应元素i-th为中心的回文子串长度. 那么问题来了: 1. ...

  7. xls表格 拼接字段 拼json =CONCAT("{ code:'",A2,"',","codeName: '",B2,"',","flag: '",C2,"'},")

    xls表格 拼接字段 拼json =CONCAT("{ code:'",A2,"',","codeName: '",B2,"',& ...

  8. python基础一day3 字符串

    对字符串进行的任何操作都是形成新的字符串. 切片顾头不顾尾 倒着取: 因为顾头不顾尾,所以4要取到 当步长省略时,可以同时省略最后一个冒号 写0时,取不到,什么都不写,可以取到 倒着取出全部的值,两种 ...

  9. JavaSE-29 Java8的Lambda表达式

    概念说明 Lambda表达式是Java8提供的新特性,支持将代码块作为方法的参数. Lambda表达式支持使用简洁的代码创建只有一个方法的接口(函数式接口). 只包含一个方法的接口也称为函数式接口. ...

  10. net core 使用ef生成实体类(SqlServer)

    1)打开程序包管理器控制台 2)输入命令  Install-Package Microsoft.EntityFrameworkCore.SqlServer 3)输入命令  Install-Packag ...