Loj #2568. 「APIO2016」烟花表演

题目描述

烟花表演是最引人注目的节日活动之一。在表演中,所有的烟花必须同时爆炸。为了确保安全,烟花被安置在远离开关的位置上,通过一些导火索与开关相连。导火索的连接方式形成一棵树,烟花是树叶,如图 1所示。火花从开关出发,沿导火索移动。每当火花抵达一个分叉点时,它会扩散到与之相连的所有导火索,继续燃烧。导火索燃烧的速度是一个固定常数。图 1展示了六枚烟花 \(\{E_1, E_2, \ldots, E_6 \}\) 的连线布局,以及每根导火索的长度。图中还标注了当在时刻 \(0\) 从开关点燃火花时,每一发烟花的爆炸时间。

图 1

Hyunmin 为烟花表演设计了导火索的连线布局。不幸的是,在他设计的布局中,烟花不一定同时爆炸。我们希望修改一些导火索的长度,让所有烟花在同一时刻爆炸。例如,为了让图 1中的所有烟花在时刻 \(13\) 爆炸,我们可以像图 2中左边那样调整导火索长度。类似地,为了让图 1中的所有烟花在时刻 \(14\) 爆炸,我们可以像图 2中右边那样调整长度。

图 2

修改导火索长度的代价等于修改前后长度之差的绝对值。例如,将图 1中布局修改为图 2,左边布局的总代价为 \(6\),而将图 1中布局修改为图 2右边布局的总代价为 \(5\)。

导火索的长度可以被减为 \(0\),同时保持连通性不变。

给定一个导火索的连线布局,你需要编写一个程序,去调整导火索长度,让所有的烟花在同一时刻爆炸,并使得代价最小。

输入格式

所有的输入均为正整数。令 \(N\) 代表分叉点的数量,\(M\) 代表烟花的数量。分叉点从 \(1\) 到 \(N\) 编号,编号为 \(1\) 的分叉点是开关。烟花从 \(N+1\) 到 \(N+M\) 编号。

输入格式如下:

\(N\:\:M\)

\(P_2\:\:C_2\)

\(P_3\:\:C_3\)

\(\ldots\)

\(P_N\:\:C_N\)

\(P_{N+1}\:\:C_{N+1}\)

\(\ldots\)

\(P_{N+M}\:\:C_{N+M}\)

其中 \(P_i\) 满足 \(1\le P_i<i\),代表和分叉点或烟花 \(i\) 相连的分叉点。\(C_i\) 代表连接它们的导火索长度 \((1\le C_i\le 10^9)\)。除开关外,每个分叉点和多于 \(1\) 条导火索相连,而每发烟花恰好与 \(1\) 条导火索相连。

数据范围与提示

子任务 1(7 分):\(N=1,1 \le M \le 100\)。

子任务 2(19 分):\(1 \le N+M \le 300\),且开关到任一烟花的距离不超过 \(300\)。

子任务 3(29 分):\(1 \le N+M \le 5000\)。

子任务 4(45 分):\(1 \le N+M \le 3\times 10^5\)。

\(\\\)

参考博客

设\(f_i(x)\)为使得\(i\)的子树中所有叶子到\(i\)距离为\(x\)所付出的代价。很明显\(f_i(x)\)是个下凸的函数,而且中间有一整段斜率为\(0\)的区间,假设为\([L,R]\)。我们先考虑已经得到了\(f_u(x)\),要加上\(u\)的父亲到\(u\)的那条边(长度为\(w\))后函数怎么变化。

\[f_{fa_u}(x)=
\begin{cases}
f_u(x)+w & x\leq L\\
f_u(L)+w-(x-L) & L\leq x\leq L+w\\
f_u(L) & L+w <x\leq R+w\\
f_u(R)+x-w-R & R+w<x
\end{cases}
\]

假设最终这条边的边权为\(w'\),最优策略就是尽量使得\(x-w'\),也就是所有叶子到\(u\)的距离尽量往\([L,R]\)靠。

我们观察这个转移,相当于将\(L\)以左的部分抬高\(w\),然后接一条斜率为\(-1\)的直线,然后接一条斜率为\(0\)的直线,最后接斜率为\(1\)的直线。也就是说先将右端的斜率大于\(0\)的直线全部删除,再加入上述三条直线。

假设我们已经完成了这个操作,于是就把这个函数加到\(fa_u\)的函数中。我们发现累加函数会使斜率逐渐增大。比如函数\(1\)在\(x\geq x_1\)的部分斜率为\(1\),函数\(2\)在\(x\geq x_2\)的部分斜率为\(1\)(\(x_1<x_2\)),那么新函数在\(x_1\leq x\leq x_2\)的部分斜率为\(1\),在\(x>x_2\)的部分斜率为\(2\)。

所以我们只需要维护函数的拐点的横坐标就行了。考虑每合并一个儿子,函数的最大斜率都会\(+1\),所以函数最右端斜率\(>0\)的端点个数就是儿子的数量。具体实现可以用可并堆。

最后考虑得到最终的函数后怎么算答案。明显答案就在那一段斜率为\(0\)的区间,但是我们只维护了横坐标。我们知道\(f_1(0)=sum\),其中\(sum\)表示所有的边长度之和。每次合并函数,最大斜率\(+1\),同理最小斜率也会\(-1\),所有函数左侧的斜率也是递减的。假设最左侧斜率\(<0\)的一堆端点有\(k\)个,分别为\(x_1,x_2,\ldots,x_k\),那么答案就

\[sum-x_1*k+\sum_{i=2}^k(x_i-x_{i-1})*(k-i+1)\\
=sum-\sum_{i=1}^kx_i
\]

代码:

#include<bits/stdc++.h>
#define ll long long
#define N 600005 using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;} int n,m;
struct tree {
int ls,rs,key;
ll val;
}tr[N<<1];
int Merge(int a,int b) {
if(!a||!b) return a+b;
if(tr[a].val<tr[b].val) swap(a,b);
tr[a].rs=Merge(tr[a].rs,b);
if(tr[tr[a].ls].key<tr[tr[a].rs].key) swap(tr[a].ls,tr[a].rs);
tr[a].key=tr[a].rs?tr[tr[a].rs].key+1:0;
return a;
}
int Pop(int a) {return Merge(tr[a].ls,tr[a].rs);} int fa[N];
int len[N];
ll sum;
int sn[N];
int rt[N];
int tot;
int main() {
n=Get(),m=Get();
for(int i=2;i<=n+m;i++) {
fa[i]=Get(),len[i]=Get();
sum+=len[i];
sn[fa[i]]++;
}
for(int i=n+m;i>=2;i--) {
ll l=0,r=0;
if(i<=n) {
while(--sn[i]) rt[i]=Pop(rt[i]);
r=tr[rt[i]].val;rt[i]=Pop(rt[i]);
l=tr[rt[i]].val;rt[i]=Pop(rt[i]);
}
tr[++tot].val=l+len[i];
tr[++tot].val=r+len[i];
rt[i]=Merge(rt[i],Merge(tot-1,tot));
rt[fa[i]]=Merge(rt[fa[i]],rt[i]);
} while(sn[1]--) rt[1]=Pop(rt[1]);
while(rt[1]) {
sum-=tr[rt[1]].val;
rt[1]=Pop(rt[1]);
}
cout<<sum;
return 0;
}

Loj #2568. 「APIO2016」烟花表演的更多相关文章

  1. 【LOJ】#2568. 「APIO2016」烟花表演

    题解 这个听起来很毒瘤的想法写起来却非常休闲,理解起来可能很费劲 例如,我们首先到猜到答案是个下凸包 然后是不是要三分???然而并不是orz 我们通过归纳证明这个下凸包的结论来总结出了一个算法 也就是 ...

  2. 「APIO2016」烟花表演

    「APIO2016」烟花表演 解题思路 又是一道 solpe trick 题,观察出图像变化后不找一些性质还是挺难做的. 首先令 \(dp[u][i]\) 为节点 \(u\) 极其子树所有叶子到 \( ...

  3. Loj #2192. 「SHOI2014」概率充电器

    Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  4. Loj #3096. 「SNOI2019」数论

    Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...

  5. Loj #3093. 「BJOI2019」光线

    Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...

  6. Loj #3089. 「BJOI2019」奥术神杖

    Loj #3089. 「BJOI2019」奥术神杖 题目描述 Bezorath 大陆抵抗地灾军团入侵的战争进入了僵持的阶段,世世代代生活在 Bezorath 这片大陆的精灵们开始寻找远古时代诸神遗留的 ...

  7. Loj #2542. 「PKUWC2018」随机游走

    Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...

  8. Loj #3059. 「HNOI2019」序列

    Loj #3059. 「HNOI2019」序列 给定一个长度为 \(n\) 的序列 \(A_1, \ldots , A_n\),以及 \(m\) 个操作,每个操作将一个 \(A_i\) 修改为 \(k ...

  9. Loj #3056. 「HNOI2019」多边形

    Loj #3056. 「HNOI2019」多边形 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时针方向标号依次为 \(1,2,3, \ldots , n\).最开 ...

随机推荐

  1. 使用php开发,基于swoole扩展开发的工具 swoole-crontab 作业/任务调度

    Swoole-Crontab(基于Swoole扩展) 1.概述 基于swoole的定时器程序,支持秒级处理. 异步多进程处理. 完全兼容crontab语法,且支持秒的配置,可使用数组规定好精确操作时间 ...

  2. 前端优化,包括css,jss,img,cookie

    前端优化,来自某懒观看麦子学院视频的笔记. 尽可能减少HTTP的请求数 使用CDN 添加Expirs头,或者Cache-control Gzip组件压缩文件内容 将CSS放在页面上方 将脚本放到页面下 ...

  3. 《细说PHP》第四版 样章 第18章 数据库抽象层PDO 3

    18.3  PDO的安装 PDO随PHP 5.1版本发行,在PHP 5的PECL扩展中也可以使用.PDO需要PHP 5版本核心面向对象特性的支持,所以它无法在之前的PHP版本中运行.无论如何,在配置P ...

  4. VS2019 MSB364 未找到框架“NETFramework,Version=v4.7”

    环境: WIN 10 VS2019 已安装框架v4.7.2 问题: 在打开一些早期项目时,编译报 MSB364 错误,未找到框架“NETFramework,Version=v4.7”或未找到框架“NE ...

  5. MySQL学习——操作自定义函数

    MySQL学习——操作自定义函数 摘要:本文主要学习了使用DDL语句操作自定义函数的方法. 了解自定义函数 是什么 自定义函数是一种与存储过程十分相似的过程式数据库对象.它与存储过程一样,都是由SQL ...

  6. Java生鲜电商平台-商品分类表和商品类型表的区别与数据库设计

    Java生鲜电商平台-商品分类表和商品类型表的区别与数据库设计   二者服务的对象不一样 目的也是不一样的 商品分类是为商品服务的 用来管理商品 商品类型是为扩展属性服务的 用来管理属性 举例:[转] ...

  7. Python【day 17-2】面向对象-成员

    '''''' ''' 1.简述面向对象三大特性并用示例解释说明?[背写] 1.封装 狭义的封装:把一组属性封装到一个对象,创建对象的时候 广义的封装:代码块,函数.对象.类.模块-py文件都是封装 把 ...

  8. dependencies和devDependencies区别

    vue-cli3.x项目的package.json中,有两种依赖: dependencies:项目依赖.在编码阶段和呈现页面阶段都需要的,也就是说,项目依赖即在开发环境中,又在生产环境中.如js框架v ...

  9. Unity API学习笔记(2)-GameObject的3种Message消息方法

    官方文档>GameObject 首先建立测试对象: 在Father中添加两个脚本(GameObejctTest和Target),分别用来发送Message和接受Message: 在其它GameO ...

  10. Ubuntu18.04安装Cuda10.1

    注:如果使用anaconda,貌似不需要手动安装Cuda和cudnn,安装tensorflow时会自动安装 1.官方教程https://docs.nvidia.com/cuda/cuda-instal ...