Loj #2568. 「APIO2016」烟花表演
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\))后函数怎么变化。
\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-\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」烟花表演的更多相关文章
- 【LOJ】#2568. 「APIO2016」烟花表演
题解 这个听起来很毒瘤的想法写起来却非常休闲,理解起来可能很费劲 例如,我们首先到猜到答案是个下凸包 然后是不是要三分???然而并不是orz 我们通过归纳证明这个下凸包的结论来总结出了一个算法 也就是 ...
- 「APIO2016」烟花表演
「APIO2016」烟花表演 解题思路 又是一道 solpe trick 题,观察出图像变化后不找一些性质还是挺难做的. 首先令 \(dp[u][i]\) 为节点 \(u\) 极其子树所有叶子到 \( ...
- Loj #2192. 「SHOI2014」概率充电器
Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...
- Loj #3096. 「SNOI2019」数论
Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...
- Loj #3093. 「BJOI2019」光线
Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...
- Loj #3089. 「BJOI2019」奥术神杖
Loj #3089. 「BJOI2019」奥术神杖 题目描述 Bezorath 大陆抵抗地灾军团入侵的战争进入了僵持的阶段,世世代代生活在 Bezorath 这片大陆的精灵们开始寻找远古时代诸神遗留的 ...
- Loj #2542. 「PKUWC2018」随机游走
Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...
- Loj #3059. 「HNOI2019」序列
Loj #3059. 「HNOI2019」序列 给定一个长度为 \(n\) 的序列 \(A_1, \ldots , A_n\),以及 \(m\) 个操作,每个操作将一个 \(A_i\) 修改为 \(k ...
- Loj #3056. 「HNOI2019」多边形
Loj #3056. 「HNOI2019」多边形 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时针方向标号依次为 \(1,2,3, \ldots , n\).最开 ...
随机推荐
- IT兄弟连 Java语法教程 流程控制语句 控制循环结构3
使用continue忽略本次循环剩下的语句 continue的功能和break有点类似,区别是continue只是忽略本次循环剩下的语句,接着开始下一次循环,并不会终止循环:而break则是完全终止循 ...
- Pycharm新手使用教程(详解)
Pycharm新手使用教程(详解) [注]: 如果想要下载Pycharm工具,直接去<开发工具>中进行下载. 简介 Jetbrains家族和Pycharm版本划分: pycharm是Jet ...
- 接口的 COM 组件调用 QueryInterface 因以下错误而失败: 库没有注册。
这个问题原因是因为安装了高版本的office然后卸载掉,又安装了低版本的office导致的. 博主是 office2016卸载后,安装了office2013. EXCEL报错信息为: 无法将类型为“M ...
- go-家庭收支记账软件例子
家庭收支记账软件项目 项目需求说明 1) 模拟实现基于文本界面的<家庭记账软件> 2) 该软件能够记录家庭的收入.支出,并能够打印收支明细表 项目的界面 看代码效果 项目代码实现 实现基本 ...
- c++11 C++14 C++17
Since C++11, WG21, the ISO designation for the C++ standard, try to shipped the standard every 3 ye ...
- Redis哨兵模式大key优化
目前,Redis哨兵模式,内存资源有限,有很多key大于500M,性能待优化.需要迁移至Redis-cluster集群中. 涉及到的key如下: 0,hash,duser_record, ...
- cmd start命令启动文件的路径
最近在脚本中通过WScript.Shell执行命令行,实现IE打开Chrome的功能. JS代码如下: var singleurl = window.location.href; var isChro ...
- RSA加密算法破解及原理
- RSA算法原理 - - 加密与解密 在RSA中,Bob想给Alice发一个消息X,Alice公钥为(e,n),私钥为(n,d). 加密和解密的过程如下: - RSA暴力破解 RSA暴力破解,简单理 ...
- 使用android日志工具
Log的级别? 日志级别按照高低排序为:ERROR,WARN,INFO,DEBUG,VERBOSE, 日志输出: Log.e()输出ERROR级别的日志信息 Log.w()输出WARN,ERROR级别 ...
- 一语点醒技术人:你不是 Google(转载)
转载链接:https://www.infoq.cn/article/2017/06/U-no-Google 在为问题寻找解决方案时要先充分了解问题本身,而不是一味地盲目崇拜那些巨头公司.Ozan On ...