一道很玄妙的题= =

我们考虑先考虑DP 那么有$f[x]=min(c+\sum f[y])$ $f[x]$表示覆盖x的子树和x->fa[x]的所有边最小代价 我们枚举一条边c覆盖的x->fa[x]并把它作为主链 f[y]就是除了主链以外的所有点的dp

接着考虑这个玩意怎么维护 我们可以在dp过程中直接把$\sum f[y]$放入$c$中 就变成了下面的这些操作

1.将终点在x的链删除。

2.记$sum=\sum f[y] y=son[x]$,son[i]子树内所有的链$c+=sum-f[son[i]]$,特别地,起点在i的链$c+=sum$。

3.取出f[x]是子树x中所有的链c的最小值。

显然这个可以数据结构维护掉

接下来我们考虑更为简洁的做法。

我们还是考虑每条向父亲的边都需要被覆盖。所以我们在覆盖x->fa[x]的时候我们是把所有的x的子树的链都合并起来然后选出一条覆盖这个边的。

直接用堆维护,这样的贪心显然是不对的。但是我们考虑用整体标记覆盖的方法。也就是取出堆顶v然后对堆中所有元素打上-v的标记 这样的话就可以选出别的链来替换掉当前的选择。这个方法非常有趣,一会写的另一道题也是用的标记覆盖的方法来维护。

然后我们在每条链的尽头需要把它删掉,实际上也不需要彻底删掉,我们只需要让它不能成为答案即可。这个在取堆顶的时候判断一下就可以了。

这个题很坑的地方就是在pop的时候需要把当前的标记下传掉,然而很多人都没有写这个地方,CF数据也较弱没有卡掉这个问题。在校内OJ上WA到自闭一度以为算法错了的我流下了悲伤的泪水TAT。

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define inf 20021225
#define ls(x) t[x].son[0]
#define rs(x) t[x].son[1]
#define N 300010
using namespace std;
int read()
{
int s=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-') f=-; ch=getchar();}
while(ch>=''&&ch<='') s=s*+ch-'',ch=getchar();
return s*f;
}
struct node{int fa,son[],dep; ll val,tag;}t[N];
struct edge{int to,lt;}e[N<<]; int in[N],cnt; ll ans;
void add(int x,int y)
{
e[++cnt].to=y; e[cnt].lt=in[x]; in[x]=cnt;
e[++cnt].to=x; e[cnt].lt=in[y]; in[y]=cnt;
}
void put(int x,ll v){if(!x) return; t[x].tag+=v,t[x].val+=v;}
void pushdown(int x)
{
if(!t[x].tag) return;
put(ls(x),t[x].tag); put(rs(x),t[x].tag);
t[x].tag=;
}
int merge(int x,int y)
{
if(!x||!y) return x|y;
if(t[y].val<t[x].val) swap(x,y);
pushdown(x); t[x].son[]=merge(t[x].son[],y);
t[ls(x)].fa=t[rs(x)].fa=x; t[x].fa=x;
if(t[rs(x)].dep>t[ls(x)].dep) swap(ls(x),rs(x));
t[x].dep=t[rs(x)].dep+; return x;
}
int rtn[N],top[N]; bool vis[N]; bool GG;
void dfs(int x,int f)
{
for(int i=in[x];i;i=e[i].lt)
{
int y=e[i].to; if(f==y) continue;
dfs(y,x); if(GG) return;
rtn[x]=merge(rtn[x],rtn[y]);
}
vis[x]=; if(x==) return;
while(vis[top[rtn[x]]]) pushdown(rtn[x]),rtn[x]=merge(ls(rtn[x]),rs(rtn[x]));
if(!rtn[x]){GG=; return;}
ans+=t[rtn[x]].val; put(rtn[x],-t[rtn[x]].val);
}
int main()
{
int n=read(),m=read();
for(int i=;i<n;i++){int x=read(),y=read(); add(x,y);}
for(int i=;i<=m;i++)
{
int x=read(); top[i]=read(); t[i].val=read();
rtn[x]=merge(rtn[x],i);
}
dfs(,);
printf("%lld\n",GG?-:ans);
return ;
}

CF671D Roads in Yusland的更多相关文章

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

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

  2. codesforces 671D Roads in Yusland

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

  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. CF671D:Roads in Yusland

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

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

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

  9. 题解-Codeforces671D Roads in Yusland

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

随机推荐

  1. 《SQL Server 2012 T-SQL基础》读书笔记 - 4.子查询

    Chapter 4 Subqueries 子查询分为:独立子查询(Self-Contained Subqueries)和相关子查询(Correlated Subqueries),独立子查询可以单独拿出 ...

  2. linux添加新硬盘不需要重启识盘,及查看uuid

     添加新物理硬盘 用ssh工具连接到服务器,执行:fdisk -l 查看磁盘,并没有新加的硬盘 fdisk -l查看硬盘及分区状态     查看主机总线号,命令:ls /sys/class/scsi_ ...

  3. (转)C#_WinForm接收命令行参数

    本文转载自:http://blog.csdn.net/lysc_forever/article/details/38356007 首先,我要仔细的声明下,本文讲的是接受命令行参数,让程序启动.而不是启 ...

  4. ConcurrentSkipListMap 源码分析

    ConcurrentSkipListMap ConcurrentSkipListMap 能解决什么问题?什么时候使用 ConcurrentSkipListMap? 1)ConcurrentSkipLi ...

  5. JS - 事件循环和任务队列

    栈.堆和队列 栈:函数调用形成栈 堆:对象的内容分配在堆中 队列:一个 JavaScript 运行时包含了一个待处理的消息队列.在事件循环期间依次处理队列中的消息 事件循环 之所以称之为事件循环,是因 ...

  6. DataFrame 结构

    概念 DataFrame 是表格型的数据结构 ,DataFrame 本质上可以看做是由series 组成的字典, 它既有行索引,也有列索引.  它并不是列表,也不是字典,.

  7. C#7.0新特性和语法糖详解

    转自IT之家网--DotNet码农:https://www.ithome.com/html/win10/305148.htm 伴随Visual Studio 2017的发布,C#7.0开始正式走上工作 ...

  8. Win10.去掉任务栏缩略图(just4explorer)

    ZC: 该方式只适用于 Explorer(即 WIndows任务管理器),Why? ∵ 看文中设置 regedit 的路径,它设置的就是 Explorer下的键值 ... 1.HKEY_CURRENT ...

  9. 前端 CSS 优先级 样式设置important

    !important 的使用. !important方式来强制让样式生效,但并不推荐使用.因为如果过多的使用!important会使样式文件混乱不易维护. 万不得已可以使用!important 现在选 ...

  10. HIbernate入门3

    HIbernate的一对多操作: 1. 创建实体类:一个Customer类(客户类)和一个LinkMan类(联系人),两者的关系为:一个客户中可能有多个联系人(关于一对多的实体类之间的关联,不做详细介 ...