【APIO2016】烟火表演
先前的题目对 slope trick 的认识还不深刻,这题可以看出一个完整的构建过程。
题目描述
给定一棵有根树,根为
算法解析
首先有朴素 dp,设
但是复杂度过大,考虑优化,发现
而且每次修改的斜率可能是
这启发我们用 slope trick 做,现在研究被合并到父亲时需要做什么变化:
这里我们想象儿子是一个图像,父亲是一个图像,要将儿子的图像
-
: 往左走, 最多减小 ,但是 增加至少 ,不优,所以取 时最优, 代价是 。 -
:发现如果 取 时 取最小值,但是 ,所以绝对值函数取不到最小值,相应地,要将 往左移一些,但是由于 斜率的原因,还是不优,所以 ,代价是 。 -
: 时绝对值和 都取最小值,两全其美,代价是 。 -
,同 ,无法向右走, ,所以代价是 。
观察这个图形发生了什么?
众所周知的是,slope trick 中我们存多个拐点代表斜率此时增加
所以我们假定我们现在知道初始值和初始斜率,这样后面的就更好理解。
-
1操作相当于将
的 部分向上平移 ,直接初始值 即可。 -
2操作相当于在刚刚的基础上,从
开始到 的一条斜率为 的直线,由于原来这一段是平的。所以这里斜率为 。 -
3操作继承原来最小值,计算发现初始值抬高了
,但是前面那段斜率为 的直线正好下降了 ,所以值直接不变。 -
4操作相当于在3的基础上,从
开始在后面连一条斜率为 的直线,直接删掉后面所有拐点,再加一个即可。
然后要将这个凸壳加到父亲上,这个使用可并堆即可,本文用了左偏树。
具体修改凸壳就是:删掉后面的一些点,在
至于这个 "一些",儿子每次合并上来,后面会增加一个,所以数儿子数量,合并所有儿子时只留一个斜率
对于
时间复杂度
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 6e5 + 5;
struct Heap{
int lc,rc,val,dis;
}t[N];
int rt[N],n,m,tot = 0,fa[N],C[N],deg[N];
inline int merge(int x,int y)
{
if(!x || !y) return x + y;
if(t[x].val < t[y].val) swap(x,y);
t[x].rc = merge(t[x].rc,y);
if(t[t[x].rc].dis > t[t[x].lc].dis) swap(t[x].rc,t[x].lc);
t[x].dis = t[t[x].rc].dis + 1;
return x;
}
inline int new_node(int v) {++tot; t[tot].lc = t[tot].rc = t[tot].dis = 0; t[tot].val = v; return tot;}
inline void push(int x,int v) {rt[x] = merge(rt[x],new_node(v));}
inline int top(int x) {return t[rt[x]].val;}
inline void pop(int x) {rt[x] = merge(t[rt[x]].lc,t[rt[x]].rc);}
signed main()
{
cin>>n>>m;
for(int i = 2;i <= n + m;i++)
{
cin>>fa[i]>>C[i];
deg[fa[i]]++;
}
for(int i = n + m;i >= 2;i--)
{
int L = 0,R = 0;
if(i <= n)
{
while(--deg[i]) pop(i);
R = top(i); pop(i);
L = top(i); pop(i);
}
push(i,L + C[i]); push(i,R + C[i]);
rt[fa[i]] = merge(rt[fa[i]],rt[i]);
}
while(--deg[1]) pop(1);
pop(1);
int ans = 0;
for(int i = 1;i <= n + m;i++) ans += C[i];
while(rt[1]) ans -= top(1),pop(1);
cout<<ans;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?