一道很玄妙的题= =

我们考虑先考虑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. django搭建一个小型的服务器运维网站

    前言   不管是运维还是开发抑或是测试,工作中不免会和Linux服务器打交道,常见的操作譬如:查看CPU或内存状态.查看和修改服务器时间.查看或者修改服务器配置文件.实时查看或回看系统的日志.重启服务 ...

  2. elementUI分页组件封装

    在实际开发需求,产品需要的分页组件比较简单,只可以一页页地翻,就是为了防止用于直接翻看最后的数据(因为有一些历史数据数据量比较大,查看的意义不大,检索效率比较低也比较忙,因为不希望用户在翻页的时候可以 ...

  3. SQL Server创建链接服务器

    1.通过sql语句创建链接服务器,数据是sql server的 EXEC sp_addlinkedserver @server='test', --链接服务器别名,自定义 @srvproduct='' ...

  4. EF6中一个关于时间类型 datetime2 的坑

    在一个访问下位机的程序中,返回的时间戳有时候因断线产生0001年01月01日的时间,而原先使用拼接SQL进行数据存储的操作时,这个问题是可以跳过的. 这次把拼接SQL的部分重新改为EF进行管理,这个坑 ...

  5. 阶段1 语言基础+高级_1-3-Java语言高级_04-集合_06 Set集合_5_HashSet存储自定义类型元素

    想存储的元素不重复,就必须重写hashCode和equals这两个方法 新建一个Person类.添加姓名和年龄这两个成员变量..get和set,有参和无参构造. 重点是重写了toString的方法 自 ...

  6. redis集群安装多端口多实例部署

    目标(本文达成的结果,配对关系可能会变): 先在131上进行操作 1.下载redis http://download.redis.io/releases/redis-5.0.2.tar.gz 2.解压 ...

  7. layui基本使用(动态获取数据,并把需要的数据传到新打开的窗口)

    <div class="xiaoxi">\n' + ' <div class="layui-row">\n' + ' <input ...

  8. C#里sqlDataAdapter.fill(DataSet,String)的用法

    第二个参数 String是指定DataSet 里表的名字,例如 sqlDataAdapter.fill(DataSet,"学生表") 指定后,以后就可以这样调用这张表 DataSe ...

  9. SpringBoot 使用logback

    1.添加pom引用 <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback ...

  10. 洛谷P1095守望者的逃离题解-伪动态规划/贪心

    链接 题目描述 恶魔猎手尤迪安野心勃勃,他背叛了暗夜精灵,率领深藏在海底的娜迦族企图叛变.守望者在与尤迪安的交锋中遭遇了围杀,被困在一个荒芜的大岛上.为了杀死守望者,尤迪安开始对这个荒岛施咒,这座岛很 ...