CF671D Roads in Yusland
一道很玄妙的题= =
我们考虑先考虑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的更多相关文章
- 【CF671D】Roads in Yusland(贪心,左偏树)
[CF671D]Roads in Yusland(贪心,左偏树) 题面 洛谷 CF 题解 无解的情况随便怎么搞搞提前处理掉. 通过严密(大雾)地推导后,发现问题可以转化成这个问题: 给定一棵树,每条边 ...
- codesforces 671D Roads in Yusland
Mayor of Yusland just won the lottery and decided to spent money on something good for town. For exa ...
- Codeforces 671 D. Roads in Yusland
题目描述 Mayor of Yusland just won the lottery and decided to spent money on something good for town. Fo ...
- [Codeforces671D]Roads in Yusland
[Codeforces671D]Roads in Yusland Tags:题解 题意 luogu 给定以1为根的一棵树,有\(m\)条直上直下的有代价的链,求选一些链把所有边覆盖的最小代价.若无解输 ...
- 【CF617D】Roads in Yusland
[CF617D]Roads in Yusland 题面 蒯的洛谷的 题解 我们现在已经转化好了题目了,戳这里 那么我们考虑怎么求这个东西,我们先判断一下是否所有的边都能被覆盖,不行的话输出\(-1\) ...
- 【CodeForces】671 D. Roads in Yusland
[题目]D. Roads in Yusland [题意]给定n个点的树,m条从下往上的链,每条链代价ci,求最少代价使得链覆盖所有边.n,m<=3*10^5,ci<=10^9,time=4 ...
- CF671D:Roads in Yusland
n<=300000个点的树,给m<=300000条带权路径(ui,vi,保证vi是ui的祖先)求覆盖整棵树每条边的最小权和. 好题好姿势!直观的看到可以树形DP,f[i]表示把点i包括它爸 ...
- 【CF671D】 Roads in Yusland(对偶问题,左偏树)
传送门 洛谷翻译 CodeForces Solution emmm,先引入一个对偶问题的概念 \(max(c^Tx|Ax \leq b)=min(b^Ty|A^Ty \ge c)\) 考虑这个式子的现 ...
- 题解-Codeforces671D Roads in Yusland
Problem Codeforces-671D 题意概要:给定一棵 \(n\) 点有根树与 \(m\) 条链,链有费用,保证链端点之间为祖先关系,问至少花费多少费用才能覆盖整棵树(\(n-1\) 条边 ...
随机推荐
- vue双向绑定原理(简单实现原理附demo)
先上效果图 简单的实现数据的双向绑定首先来了解一个东西:Object.defineProperty() https://developer.mozilla.org/zh-CN/docs/Web/Jav ...
- mysql分组,行转列
aaarticlea/jpeg;base64,/9j/4QEsRXhpZgAASUkqAAgAAAAPAJqCCgABAAAAwgAAABABAgAQAAAAygAAAAABAwABAAAAQBAAA
- 用 MuGo 搭建 Go Engine 在 KGS 对战
MuGo 是一个开源的 Go Engine,下棋能力大概在 10k - 2k 左右. 用 MuGo 搭建 Go Engine 并在 KGS 对战的步骤如下: 1. 安装 TensorFlow 因为 M ...
- PROD异机全备份恢复验证实施文档
PROD异机全备份恢复验证实施文档 ******利用10月25日的全量备份.10月26日当天的归档日志及当前redo日志,恢复数据库到故障前数据库状态****** 准备工作:source 源库:PRO ...
- qbzt day5 下午
农场主John新买了一块长方形的新牧场,这块牧场被划分成M行N列(1 ≤ M ≤ 12; 1 ≤ N ≤ 12),每一格都是一块正方形的土地.John打算在牧场上的某几格里种上美味的草,供他的奶牛们享 ...
- netstat和ps
ps是查看进程, 主要是针对本机的, 进程活动, 更多的是关注性能, 关注对机器 资源的使用清况 netstat是查看网络状态, 主要是针对网络的.是查看网络上, 对内网 外网的活动情况, 更多的是关 ...
- leetcode 36有效的数独
建立一个哈希表,每次查找,如果对应的列col,行row,小方格box中的数出现第二次,那么数独不合法: 据说还有深度优先搜索的方法,表示没有听懂:) class Solution { public: ...
- 用Vue来实现音乐播放器(八):自动轮播图啊
slider.vue组件的模板部分 <template> <div class="slider" ref="slider"> <d ...
- 阶段1 语言基础+高级_1-3-Java语言高级_03-常用API第二部分_第5节 StringBuilder类_1_StringBuilder的原理
字符串不可变.字符串的缓冲区是可以变的 字符串Sting的底层,被final修饰的不可变的数组 a+b+c最终会产生5个字符串
- 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_04 IO字节流_5_文件存储的原理和记事本打开文本显示原理
原理 流对象指向这个文件a.txt 往文件中写数据,写的时候比较特殊 97转换成二进制是多少呢? 输入97然后选择二进制.转换后为 1100001 硬盘上实际存的是97的二进制 97查询阿斯克码表就是 ...