http://uoj.ac/problem/205

好神的题啊。

dp[i][j]表示以i为根的子树调整成长度j需要的最小代价。

首先要观察到dp值是一个下凸壳。

因为从儿子合并到父亲时要把所有儿子的凸壳相加,得到的还是一个凸壳。

父亲要把它连向它父亲的边的影响加入时,设这条边长度为len,则相当于把当前的这个凸壳先右移len,斜率大于1的部分斜率都重置为1,斜率小于1的部分都向左移len再向上移len,其中空出来的长度为len的部分用斜率为-1的连接起来。

就是把原凸壳先整体上移len,再删掉斜率大于等于0的部分,再添上3条斜率分别为-1,0,1的直线。

直接维护凸壳的复杂度是\(O\left((n+m)^2\right)\)的。

再来考虑一下凸壳的性质:

一个凸壳在x=0处的取值是子树内所有边权和;

当这个凸壳没有考虑当前点到它父亲的边的贡献时,这个凸壳最右端的直线的斜率是它的儿子数;

凸壳上的直线的斜率只可能是整数;

现在有了上面的性质,可以更简单地表达一个凸壳。

有了凸壳在x=0处的取值,我们只要知道一个凸壳的导函数就可以还原出一个凸壳。

有了凸壳最右端直线的斜率,也就是导函数的最大值,我们只要知道一个凸壳的二阶导就可以还原出凸壳的导函数。

也就是说不用维护凸壳,直接维护凸壳的二阶导数就可以了。

二阶导可以更直观的看成拐点,每个在第i个位置的拐点对二阶导的贡献为1(拐点的位置可以重叠)。

每次合并时直接合并两个拐点集合就可以了,每次考虑父亲边的贡献时删掉最靠右边的儿子数+1个拐点,再添加两个拐点。

因为每次都删权值最大的拐点,拐点集合可以用可并堆维护。

最后用根节点的拐点集合还原出根节点的凸壳就可以了。

每个节点只可能加进来两个拐点,每个拐点最多被弹出一次,时间复杂度\(O\left((n+m)\log(m+m)\right)\)。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll; const int N = 600003; struct node {
node *ch[2];
int v; ll pos;
node(ll _pos = 0) : pos(_pos) {ch[0] = ch[1] = 0; v = 0;}
} *rt[N]; int dist(node *r) {return r ? r->v : -1;} node *merge(node *l, node *r) {
if (l == 0) return r;
if (r == 0) return l;
if (l->pos < r->pos) swap(l, r);
l->ch[1] = merge(l->ch[1], r);
if (dist(l->ch[0]) < dist(l->ch[1]))
swap(l->ch[0], l->ch[1]);
if (l->ch[1]) l->v = l->ch[1]->v + 1;
else l->v = 0;
return l;
} void pop(node *&r) {
if (r) r = merge(r->ch[0], r->ch[1]);
} ll sum = 0, pp[N << 1];
int fa[N << 1], len[N << 1], n, m, d[N << 1]; int main() {
scanf("%d%d", &n, &m);
for (int i = 2; i <= n + m; ++i) {
scanf("%d%d", fa + i, len + i);
sum += len[i];
++d[fa[i]];
} node *n1, *n2;
for (int i = n + m; i > 1; --i) {
if (i > n) {
rt[i] = merge(new node(len[i]), new node(len[i]));
rt[fa[i]] = merge(rt[fa[i]], rt[i]);
continue;
}
while (--d[i]) pop(rt[i]);
n2 = rt[i]; pop(rt[i]);
n1 = rt[i]; pop(rt[i]);
rt[i] = merge(rt[i], new node(n1->pos + len[i]));
rt[i] = merge(rt[i], new node(n2->pos + len[i]));
rt[fa[i]] = merge(rt[fa[i]], rt[i]);
} while (d[1]--) pop(rt[1]);
int ptot = 0;
while (rt[1]) {
pp[++ptot] = rt[1]->pos;
pop(rt[1]);
} ll prepos = 0;
while (ptot) {
if (pp[ptot] != prepos) {
sum -= (pp[ptot] - prepos) * ptot;
prepos = pp[ptot];
}
--ptot;
} printf("%lld\n", sum);
return 0;
}

【UOJ #205】【APIO 2016】Fireworks的更多相关文章

  1. 【UOJ #206】【APIO 2016】Gap

    http://uoj.ac/problem/206 对于T=1,直接从两端往中间跳可以遍历所有的点. 对于T=2,先求出最小值a和最大值b,由鸽巢原理,答案一定不小于\(\frac{b-a}{N-1} ...

  2. 【UOJ #204】【APIO 2016】Boat

    http://uoj.ac/problem/204 肯定要离散化的,先离散化出\(O(n)\)个取值区间. 设\(f(i,j)\)表示第\(i\)所学校派出的划艇数量在\(j\)区间中. \(f(i, ...

  3. UOJ 275. 【清华集训2016】组合数问题

    UOJ 275. [清华集训2016]组合数问题 组合数 $C_n^m $表示的是从 \(n\) 个物品中选出 \(m\) 个物品的方案数.举个例子,从$ (1,2,3)(1,2,3)$ 三个物品中选 ...

  4. UOJ #269. 【清华集训2016】如何优雅地求和

    UOJ #269. [清华集训2016]如何优雅地求和 题目链接 给定一个\(m\)次多项式\(f(x)\)的\(m+1\)个点值:\(f(0)\)到\(f(m)\). 然后求: \[ Q(f,n,x ...

  5. [UOJ#276]【清华集训2016】汽水

    [UOJ#276][清华集训2016]汽水 试题描述 牛牛来到了一个盛产汽水的国度旅行. 这个国度的地图上有 \(n\) 个城市,这些城市之间用 \(n−1\) 条道路连接,任意两个城市之间,都存在一 ...

  6. UOJ #274. 【清华集训2016】温暖会指引我们前行 [lct]

    #274. [清华集训2016]温暖会指引我们前行 题意比较巧妙 裸lct维护最大生成树 #include <iostream> #include <cstdio> #incl ...

  7. 【模拟】【数学】CSU 1803 2016 (2016湖南省第十二届大学生计算机程序设计竞赛)

    题目链接: http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1803 题目大意: 给定n,m(n,m<=109)1<=i<=n,1& ...

  8. 【UOJ】67 新年的毒瘤 &【BZOJ】1123 BLO

    [UOJ 67] 题目链接: 传送门 题解: 第一眼很懵逼……这什么鬼. 思考什么点复合条件……(o(>﹏<)o 1.树,也就是说还剩n-2条边,等价于要删去一个度数为m-n+2的点. 2 ...

  9. 【UOJ#236】[IOI2016]railroad(欧拉回路,最小生成树)

    [UOJ#236][IOI2016]railroad(欧拉回路,最小生成树) 题面 UOJ 题解 把速度看成点,给定的路段看成边,那么现在就有了若干边,然后现在要补上若干边,以及一条\([inf,\) ...

随机推荐

  1. 一款已上市MMO手游地图同步方案总结

    1. 客户端地图格子的相关知识 在2.5D的MMO游戏里,角色是通过3D的方式渲染,2D的地图是通过2D的方式显示,所以在客户端一般会有三个坐标系: a) 3D坐标系:所有需要3D渲染的角色和光效,都 ...

  2. 64_p7

    python-flask-whooshalchemy-0.6-10.fc26.noarch.rpm 12-Feb-2017 11:04 51894 python-flask-wtf-0.10.0-8. ...

  3. koa中间层 文件下载的请求转发

    背景: 前端用a标签发起下载文档的get请求 node中间层接到get请求后将请求转发到java后端 java后端返回文档流传递给node中间层 好处: 后端的java业务逻辑层接口.数据库不向外部暴 ...

  4. 函数参数 f_arg, *args, **kwargs

    当需要给函数传参时,可以通过运用不同的形参来传递,达到参数不同的使用目的. 简单来说:f_arg就是传递的第一个参数,类似于C++中的普通参数: *args 传递的是一个参数的list: **kwar ...

  5. 【Learn】CSS定义

    CSS基础语法 本文用于介绍CSS相关的知识,用于记录自己的学习笔记.由于我已经熟悉了部分的HTML,所以相关的概念也不在这里进行描述了,直接写自己的一些心得感悟. 1.CSS规则 CSS是由两个主要 ...

  6. .NET连接Oracle的方法

    .NET连接Oracle的方法 方式1:直接利用.NET的oracle驱动连接 引用System.data.oracleclient; using System.data.oracleclient; ...

  7. ssh连接不上排查方法总结

    //常见报错信息 # No route to host --> server端没有开机或是网络不通(这个原因很多,最简单的是网线没有插.还有就是可能会是网卡down了等) 如果是网卡down了i ...

  8. spring源码解析--事务篇(前篇)

    对于每一个JAVA程序员,spring应该是再熟悉不过的框架了,它的功能有多强大我就不多说了,既然他有这么强大的功能,是如何实现的呢?这个就需要从他的原理去了解,而最直接了解原理的方式莫过于源码.当然 ...

  9. storm的acker机制

    一.简介: storm中有一个很重要的特性: 保证发出的每个tuple都会被完整处理.一个tuple被完全处理的意思是: 这个tuple以及由这个tuple所产生的所有的子tuple都被成功处理.如果 ...

  10. 深度学习方法(八):自然语言处理中的Encoder-Decoder模型,基本Sequence to Sequence模型

    欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld.技术交流QQ群:433250724,欢迎对算法.技术感兴趣的同学加入. Encoder-Decoder(编码- ...