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) & 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 600005using 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;
}

转载于:https://www.cnblogs.com/hchhch233/p/10941732.html

Loj #2568. 「APIO2016」烟花表演相关推荐

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

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

  2. 「APIO2016」烟花表演

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

  3. Loj #3111. 「SDOI2019」染色

    Loj #3111. 「SDOI2019」染色 题目描述 给定 \(2 \times n\) 的格点图.其中一些结点有着已知的颜色,其余的结点还没有被染色.一个合法的染色方案不允许相邻结点有相同的染色 ...

  4. Loj #3055. 「HNOI2019」JOJO

    Loj #3055. 「HNOI2019」JOJO JOJO 的奇幻冒险是一部非常火的漫画.漫画中的男主角经常喜欢连续喊很多的「欧拉」或者「木大」. 为了防止字太多挡住漫画内容,现在打算在新的漫画中用 ...

  5. LOJ#2230. 「BJOI2014」大融合

    LOJ#2230. 「BJOI2014」大融合 题目描述 小强要在$N$个孤立的星球上建立起一套通信系统.这套通信系统就是连接$N$个点的一个树.这个树的边是一条一条添加上去的. 在某个时刻,一条边的 ...

  6. loj#2143. 「SHOI2017」组合数问题

    loj#2143. 「SHOI2017」组合数问题 题目描述 Solution 考虑转化一下我们要求的东西. ∑i=0n(nkik+r)=∑i=0n(nki)[i≡r(modk)]\sum_{i=0} ...

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

    LOJ#2542. 「PKUWC2018」随机游走 题目描述 Solution 去过一个点集中所有节点的期望时间不好求,考虑min−maxmin-maxmin−max容斥,转化为求第一次到达某一个点集 ...

  8. LOJ#2145. 「SHOI2017」分手是祝愿

    LOJ#2145. 「SHOI2017」分手是祝愿 题目描述 Solution 首先有一个结论: 灯的状态序列a1,a2...ana_1,a_2...a_na1​,a2​...an​唯一对应了一个最优 ...

  9. Loj #2585. 「APIO2018」新家

    Loj #2585. 「APIO2018」新家 题目描述 五福街是一条笔直的道路,这条道路可以看成一个数轴,街上每个建筑物的坐标都可以用一个整数来表示.小明是一位时光旅行者,他知道在这条街上,在过去现 ...

最新文章

  1. 活动报名|“悟道之巅:AI创新应用大赛”发布会——体验未来技术,赢取百万奖金...
  2. python的cfg是什么模块_cfg4py:一个严肃的Python配置模块应有的风格-层级式、部署环境自适应、自动补全...
  3. Exchange 2010和Exchange 2016共存部署-10:配置多域名证书
  4. angular5 httpclient的示例实战
  5. 将替代ListView的RecyclerView 的使用(一)
  6. mysql去掉两个最高分_数据分析系列 16/32 | MySQL中子查询与联合查询
  7. 十一、 C++特性之begin()与end()
  8. 使用async读取异步数据
  9. 计算机驱动伺服的程序,伺服调试软件V-ASSISTANT始终找不到驱动-工业支持中心-西门子中国...
  10. [ActionScript 3.0] 通过as3操作web内容
  11. 费尔个人防火墙采用两种封包过滤技术
  12. mysql 用户及权限
  13. 论文笔记 Inverting Visual Representations with Convolutional Networks
  14. python :tushare 唐奇安通道
  15. 洛谷 P3604 美好的每一天
  16. android+客户端+教程,Android新浪客户端开发教程完整版.pdf
  17. 下一个风电”黑马“诞生,数字孪生 3D 智慧风电
  18. 通过1997年拓荒者号飞行器事件理解优先级反转
  19. 【头部姿态】头部姿态检测(一)
  20. Python基础-EMS系统

热门文章

  1. 搜狗输入法语音转文字的体验点
  2. Python闭包基本介绍与作用
  3. Chrome浏览器截取全屏(无需安装任何插件)
  4. pycharm出现KeyError:“Couldn't find filed google.ptotobuf.FileOption.javanano_use_deprecated_package”
  5. 万万没 想到,Redis性能测试还能这样做
  6. matlab consumption,Lesage matlab 空间
  7. swing tree 去掉双击默认展开 关闭_如何保护自己的电脑,关闭危险端口(一)
  8. python global用法_Python 虚拟环境全知道
  9. 派尼数据库连接池配置
  10. python requests.get无法取出网页_Python requests获取网页常用方法解析