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. AJPFX总结Java 程序初始化过程

    觉得Core Java在Java 初始化过程的总体顺序没有讲,只是说了构造器时的顺序,作者似乎认为路径很多,列出来比较混乱.我觉得还是要搞清楚它的过程比较好.所以现在结合我的学习经验写出具体过程: 过 ...

  2. P1303 A*B Problem

    题目描述 求两数的积. 输入输出格式 输入格式: 两个数 输出格式: 积 输入输出样例 输入样例#1: 1 2 输出样例#1: 2 说明 需用高精 #include<iostream> # ...

  3. 成为Android高手必须掌握的8项基本要求

    [1] Android操作系统概述 1. Android系统架构. 2. Android利用设计理念. 3. Android 开源知识. 4. Android 参考网站与权威信息.[2] Androi ...

  4. 程序员必须知道FTP命令

                                             程序员必须知道FTP命令 文件传输软件的使用格式为:FTP<FTP地址>,若连 接成功,系统将提示用户输入 ...

  5. ubuntu 下service php5-fpm restart 报错 stop: Unknown instance: 解决

    问题描述: 在安装完扩展后,重启php-fpm,发现一直停止报错 stop: Unknown instance: 通过查看进程,也查询不到该主进程 解决办法: 干掉现在正在执行的进程 pkill ph ...

  6. 如何通过Java代码判断当前的环境是否支持JRE 9

    JDK9已经出来有一段时间了,因此很多流行的Java应用纷纷增添了对JDK9乃至JDK10的支持,比如Tomcat. 我们通过这个链接下载最新的Tomcat源文件包,总共7MB: https://to ...

  7. Windows 7桌面显示图标窗口句柄的获取

    在windows XP时代,我们获取桌面图标窗口的句柄往往用一下语句: HWND hwndParent = ::FindWindow( "Progman", "Progr ...

  8. OpenCV2:第六章 图像几何变换

    一.简介 图像的几何变换有距离变换 坐标映射 平移  镜像 旋转  缩放  仿射变换等 二.重映射 把一张图像重新排列像素,比如倒置 CV_EXPORTS_W void remap( InputArr ...

  9. windwos .bat脚本大全

    记录一个很有用比较全面的windows .bat脚本网站 https://www.cnblogs.com/zhaoqingqing/p/4620402.html

  10. “xxxx”表 - 无法修改表。 不能将值 NULL 插入列 'xxxx'

    问题 向已有表增加字段 执行下面sql,sql执行增加两个字段分别: articleTitle 正标题 [nvarchar](200) articleSubTitle 副标题 [nvarchar](2 ...