题目链接

题目要求我们求出选出若干条路径并最小化花费,如果这是在链上,我们可以考虑直接枚举每条路径的右端点 dp,那树呢?把路径剖分整个覆盖的集合就不一定连续了,没法 dp,况且题目里给了很强的条件:路径一定是从孩子到祖先,硬转链用不上这个性质,貌似不太对。

上述思考启发我们利用树的形态设计算法,而利用节点的子树分割成子问题是一个通常的思考方向,我们从此处入手,考虑如果要覆盖一棵树需要什么条件,首先,根节点的每棵子树必须被覆盖,并且还要有一条能向外延伸的边以覆盖连接根节点和子树根节点的边。

考虑设计 dp 以维护上述条件,为了维护前者,我们可以钦定每个节点的状态所选择的解中子树全部被覆盖;而后者,由于子树内所有节点的祖先并都在固定的一条链上,我们可以添加一维确定向外延伸的长度。具体地,我们设 \(f_{u,j}\) 表示完全覆盖节点 \(u\) 的子树且向外延伸了 \(j\) 个长度的最小花费。

转移是显然的,设 \(g_u=\min f_{u,j}\),则 \(f_{u,j}=\min \{f_{v,j}\}+\sum_{k\in son(v)} g_k -g_v\)。这个做法是 \(O(n^2)\) 的。

由于转移比较简单,我们考虑能不能用数据结构维护第二维,需要支持合并取 min 和全局加,用线段树合并就可以维护,时间和空间复杂度都是 \(O((n+m)\log n)\) 的。

但是本题空间复杂度限制比较紧,注意到线段树中有很多没有用的节点,并且不能动态调整空间。考虑换成平衡树,每个节点储存二元组 \((j,cost)\) 表示向上延伸 \(j\) 距离花费 \(cost\),全局加可以直接打标记,合并可以直接启发式合并,全部插到里面就行,注意为了保证复杂度,如果有向上延伸相同距离的状态我们只能保留一个。

问题是取 min,由于刚才我们已经要求平衡树按第一维排序,我们不好直接求全局 min,但是注意到如果一个状态相比于另一个能覆盖更前面的边但是花费也更小,我们不必保留另一个状态,因此在满足一维排好序的情况下另一位也排好了。平衡树可以用 set,时间复杂度 \(O((n+m)\log^2 n)\),但是空间复杂度变成了线性,可以通过。

// Problem: Roads in Yusland
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF671D
// Memory Limit: 250 MB
// Time Limit: 4000 ms
//
// Powered by CP Editor (https://cpeditor.org) #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<set>
#define ll long long
#define N 300005
using namespace std;
ll read(){
ll x=0;char ch=getchar();
while(ch<'0' || ch>'9') ch=getchar();
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x;
}
ll e,head[N<<1],nex[N<<1],to[N<<1],dep[N],tag[N],rt[N];
struct Node{
ll num,val;
bool operator <(const Node &x)const{
return num>x.num;
}
};
vector<Node> E[N];
set<Node> t[N];
void add(ll u,ll v){
to[++e]=v;nex[e]=head[u];head[u]=e;
to[++e]=u;nex[e]=head[v];head[v]=e;
}
ll flag;
void insert(ll u,ll num,ll val){
if(t[u].size()==0){t[u].insert((Node){num,val});return;}
auto it=t[u].lower_bound((Node){num,val});
if(it==t[u].end() || (it->num)!=num){
if(it!=t[u].end() && it->val<=val)return;
if(it==t[u].begin()){t[u].insert((Node){num,val});return;}
auto itr=it,itl=it;
while(itl!=t[u].begin()){
itl--;if(itl->val<val){itl++;break;}
}
if(itl!=itr)t[u].erase(itl,itr);
t[u].insert((Node){num,val});return;
}
if(it->val<=val) return;
it++;auto itr=it;it--;
while(it!=t[u].begin()){
it--;if(it->val<val){it++;break;}
}
t[u].erase(it,itr);
t[u].insert((Node){num,val});
}
void dfs(ll u,ll fa){
rt[u]=u;
ll tot=0;dep[u]=dep[fa]+1;
for(ll i=head[u];i;i=nex[i]){
ll v=to[i];if(v==fa) continue;
dfs(v,u);if(flag) return;
if(t[rt[v]].size()==0){flag=1;return;}
if((t[rt[v]].begin()->num)>dep[u])t[rt[v]].erase(t[rt[v]].begin());
if(t[rt[v]].size()==0){flag=1;return;}
tot+=(t[rt[v]].begin()->val+tag[v]);tag[v]=-(t[rt[v]].begin()->val);
}
ll tmp=300001;
for(ll i=head[u];i;i=nex[i]){
ll v=to[i];if(v==fa) continue;
if(t[rt[v]].size()>t[rt[u]].size()){tmp=v;rt[u]=rt[v];tag[u]=tot+tag[v];}
}
for(ll i=head[u];i;i=nex[i]){
ll v=to[i];if(v==fa || rt[v]==rt[u]) continue;
for(auto it=t[rt[v]].begin();it!=t[rt[v]].end();it++){
insert(rt[u],it->num,it->val+tag[v]-tag[tmp]);
}
}
for(ll i=0;i<E[u].size();i++){
insert(rt[u],dep[E[u][i].num],E[u][i].val-tag[tmp]);
}
}
int main(){
ll n,m,u,v,w;n=read();m=read();
for(ll i=1;i<n;i++){u=read();v=read();add(u,v);}
for(ll i=1;i<=m;i++){
u=read();v=read();w=read();E[u].push_back((Node){v,w});
}
if(n==1){cout<<0;return 0;}
dfs(1,0);
if(flag) cout<<-1;
else cout<<(t[rt[1]].begin()->val)+tag[1];
return 0;
}

CF671D Roads in Yusland 题解的更多相关文章

  1. CF671D Roads in Yusland

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

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

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

  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. 题解-Codeforces671D Roads in Yusland

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

  9. CF671D:Roads in Yusland

    n<=300000个点的树,给m<=300000条带权路径(ui,vi,保证vi是ui的祖先)求覆盖整棵树每条边的最小权和. 好题好姿势!直观的看到可以树形DP,f[i]表示把点i包括它爸 ...

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

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

随机推荐

  1. P3755 [CQOI2017]老C的任务题解

    如果询问 \(x_1, y_1, x_2, y_2\), 那么询问 \((x_2, y_2)\), \((x_2, y_1 - 1)\), \((x_1 - 1, y_2)\) \((x_1 - 1, ...

  2. 图像处理_Retinex图像增强

    单尺度SSR (Single Scale Retinex) 图像 S ( x , y ) S(x,y) S(x,y)分解为两个不同的图像:反射图像 R ( x , y ) R(x,y) R(x,y), ...

  3. 关于 yield 关键字(C#)

    〇.前言 yield 关键字的用途是把指令推迟到程序实际需要的时候再执行,这个特性允许我们更细致地控制集合每个元素产生的时机. 对于一些大型集合,加载起来比较耗时,此时最好是先返回一个来让系统持续展示 ...

  4. Java与PHP的区别

    1.PHP暂时不支持像Java那样的JIT运行时编译的热点代码,但PHP具有opcache机制,能够将脚本对应的opcode缓存在内存中. 补充:JIT与JVM的三种执行模式:解释模式.编译模式.混合 ...

  5. pycharm中使用命令行

    //调用django命令 tools->Run manage.py... ->弹出窗口->输入命令,回车 //创建appstartapp [appname] //数据库迁移makem ...

  6. excel:if语句

    IF语法格式: IF(logical_test,value_if_true,value_if_false) 释义:判断一个条件是否满足,如果满足返回一个值,如果不满足则返回另一个值. logical_ ...

  7. 在webpack中这样分离环境和代码就好啦

    前面的文章中,webpack.config.js 中包含本地调试和线上发布的所有配置,编译后的 bundle.js 包含所有的代码. 当项目变大.代码量变多.配置增加的时候,文件的可维护性会越来越差, ...

  8. PyCharm的基础了解

    简单了解PyCharm PyCharm的简单使用 修改主题 1 2 切换解释器 1 如何创建pythin文件 1 2 3 4 注释语法 行注释 这里是注释 块注释 '''这里是注释''' 常量和变量的 ...

  9. 《Python魔法大冒险》 001 序章:少年小鱼的不平凡一天

    在一个普通的城市里,生活着一个名叫小鱼的少年.他是一名初中生,但在班级里,他的学习成绩总是垫底.同学们经常取笑他,有时甚至戏称他为"倒数王". 放学后,小鱼一个人走在回家的路上,他 ...

  10. 入门篇-其之二-Java基础知识

    目录 对第一个Java程序的思考 外层结构--类 内层结构--main方法 输出语句 注释 单行注释 多行注释 文档注释 文档注释常用标签 使用javadoc命令生成网页风格的文档 阿里巴巴Java开 ...