【loj2568】【APIO2016】【学习笔记 左偏树】烟花表演
题目
一棵树,\(n\)个非叶子节点,编号为\(1-n\),\(m\)个叶子节点,编号为\(n+1-n+m\)
每条边有边权,修改边权的代价为\(|a-b|\) ;
定义一个叶子的距离为到1(根节点)的边的长度之和;
求最小的修改代价使得最后所有叶子的距离相同;
$1 \le M \le 300000 $
题解
(做完这个题之后有一种为什么uoj的好评只能点一次的遗憾)
设\(f(x)\)表示最终距离为\(x\)的答案,对于叶子是下凸的并且每段都是一次函数,归纳都满足这个性质的并设最值的区间为\([L,R]\) ,注意到这一段的\(f'_u\)为0,左边<=-1,右边>=1,考虑转移:
\[f_u(x) = \sum_{v} min_{k=0}^x \{ f_v(x-k) + |w-k| \} \\
考虑单个的v:\\
f_u(x) = \begin{cases}
f_v(x) + w & x \le L \\
f_v(L) + w-(x-L) & L \lt x \le L+w \\
f_v(L) & L+w \lt x \le R+w \\
f_v(R) + (x-R)-w & R+w \lt x \\
\end{cases}
\\也即把[0,L]向上平移w个单位,[L,R]向右移动w个单位;
\\中间用斜率为-1的线连接,再从R+w作一条斜率为1的射线;
\\所有v相加仍然是凸的
\]这里有详细的说明,不过建议自己脑补一下
斜率是连续的,设交点横坐标分别为\(x_m,x_m-1,\cdots,x_1,\cdots\), $ x_i $ 的左边斜率 $ =-i $ ,规定\(x_{m+1}\)为\(0\)
\[ans = f_1(0) + \sum_{i=1}^{m}-i(x_i-x_{i+1}) = f_1(0) + \sum_{i=1}^{m} -x_i \\
f_1(0)=\sum w
\]维护交点,所有\(f_v\)相加即交点集合合并,可以知道此时最大的斜率为\(|v|-1\)直接再删除那么多个交点即可;
用可并堆维护,我写的左偏树;
#include<bits/stdc++.h>
#define ll long long
#define mk make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;
const int N=600010;
int n,m,ls[N],rs[N],rt[N],sz,ds[N];
ll wv[N];
typedef pair<int,int>pii;
vector<pii>g[N];
bool cmp(int a,int b){return wv[a]==wv[b]?a<b:wv[a]<wv[b];}
char gc(){
static char*p1,*p2,s[1000000];
if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
return(p1==p2)?EOF:*p1++;
}
int rd(){
int x=0;char c=gc();
while(c<'0'||c>'9')c=gc();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc();
return x;
}
int merge(int x,int y){
if(!x||!y)return x+y;
if(cmp(x,y))swap(x,y);
rs[x]=merge(rs[x],y);
if(ds[ls[x]]<ds[rs[x]])swap(ls[x],rs[x]);
ds[x]=ds[rs[x]]+1;
return x;
}
int main(){
// freopen("fireworks.in","r",stdin);
// freopen("fireworks.out","w",stdout);
ll ans=0;n=rd();m=rd();
for(int i=2;i<=n+m;++i){
int u=rd(),w=rd();
g[u].pb(mk(i,w));
ans+=w;
}
for(int i=n+1;i<=n+m;++i)rt[i]=++sz,rs[rt[i]]=++sz;
for(int i=n;i;--i){
int d=(int)g[i].size();
for(int j=0;j<d;++j){
int v=g[i][j].fi,w=g[i][j].se;
wv[rt[v]]+=w;
if(cmp(ls[rt[v]],rs[rt[v]]))wv[rs[rt[v]]]+=w;
else wv[ls[rt[v]]]+=w;
rt[i]=merge(rt[i],rt[v]);
}
for(int j=1;j<d;++j)rt[i]=merge(ls[rt[i]],rs[rt[i]]);
}
rt[1]=merge(ls[rt[1]],rs[rt[1]]);
while(rt[1]){
ans-=wv[rt[1]];
rt[1]=merge(ls[rt[1]],rs[rt[1]]);
}
cout<<ans<<endl;
return 0;
}
【loj2568】【APIO2016】【学习笔记 左偏树】烟花表演的更多相关文章
- 左偏树 / 非旋转treap学习笔记
背景 非旋转treap真的好久没有用过了... 左偏树由于之前学的时候没有写学习笔记, 学得也并不牢固. 所以打算写这么一篇学习笔记, 讲讲左偏树和非旋转treap. 左偏树 定义 左偏树(Lefti ...
- bzoj 4585: [Apio2016]烟火表演【左偏树】
参考:https://blog.csdn.net/wxh010910/article/details/55806735 以下课件,可并堆部分写的左偏树 #include<iostream> ...
- [luogu3377][左偏树(可并堆)]
题目链接 思路 左偏树的模板题,参考左偏树学习笔记 对于这道题我是用一个并查集维护出了哪些点是在同一棵树上,也可以直接log的往上跳寻找根节点 代码 #include<cstdio> #i ...
- POJ3016-K-Monotonic(左偏树+DP)
我觉得我要改一下签名了……怎么会有窝这么啰嗦的人呢? 做这题需要先学习左偏树<左偏树的特点及其应用> 然后做一下POJ3666,这题的简单版. 思路: 考虑一下维护中位数的过程原数组为A, ...
- 左偏树初步 bzoj2809 & bzoj4003
看着百度文库学习了一个. 总的来说,左偏树这个可并堆满足 堆的性质 和 左偏 性质. bzoj2809: [Apio2012]dispatching 把每个忍者先放到节点上,然后从下往上合并,假设到了 ...
- [JLOI2015]城池攻占 左偏树
题目描述 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池.这 n 个城池用 1 到 n 的整数表示.除 1 号城池外,城池 i 会受到另一座城池 fi 的管辖,其中 fi &l ...
- 浅谈左偏树在OI中的应用
Preface 可并堆,一个听起来很NB的数据结构,实际上比一般的堆就多了一个合并的操作. 考虑一般的堆合并时,当我们合并时只能暴力把一个堆里的元素一个一个插入另一个堆里,这样复杂度将达到\(\log ...
- 【左偏树】【P3261】 [JLOI2015]城池攻占
Description 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池.这 n 个城池用 1 到 n 的整数表示.除 1 号城池外,城池 i 会受到另一座城池 fi 的管辖,其 ...
- hdu 1512 Monkey King 左偏树
题目链接:HDU - 1512 Once in a forest, there lived N aggressive monkeys. At the beginning, they each does ...
随机推荐
- Zipkin存储Sleuth信息实现调用链追踪的几种方法
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/alva_xu/article/detail ...
- WPF 很少人知道的科技
原文:WPF 很少人知道的科技 本文介绍不那么常见的 WPF 相关的知识. 本文内容 在 C# 代码中创建 DataTemplate 多个数据源合并为一个列表显示 使用附加属性做缓存,避免内存泄漏 使 ...
- 1 matplotlib绘制折线图
from matplotlib import pyplot as plt #设置图形大小 plt.figure(figsize=(20,8),dpi=80) plt.plot(x,y,color=&q ...
- C# List<string>之间的转换
List<string> 转换为 string List<string> list = new List<string>(); list.Add("a&q ...
- loj#10012\poj2018 Best Cow Fences(二分)
题目 #10012 「一本通 1.2 例 2」Best Cow Fences 解析 有序列\(\{a_i\}\),设\([l,r]\)上的平均值为\(\bar{x}\),有\(\sum_{i=l}^r ...
- Java自学-Scanner类
使用Scanner读取数据 System.out.println("") 用于向控制台输出数据. 我们还需要从控制台输入数据,所以需要用到Scanner类. 步骤 1 : 使用Sc ...
- MySQL数据库之互联网常用分库分表方案
一.数据库瓶颈 不管是IO瓶颈,还是CPU瓶颈,最终都会导致数据库的活跃连接数增加,进而逼近甚至达到数据库可承载活跃连接数的阈值.在业务Service来看就是,可用数据库连接少甚至无连接可用.接下来就 ...
- JavaScript变量存储浅析(一)
Hello! 上一篇关于JS中函数传参(http://www.cnblogs.com/souvenir/p/4969092.html)的介绍中提到了JS的另外一个基本概念:JS变量存储, 今天我们就用 ...
- Jenkins详细教程
大纲 1.背景 在实际开发中,我们经常要一边开发一边测试,当然这里说的测试并不是程序员对自己代码的单元测试,而是同组程序员将代码提交后,由测试人员测试: 或者前后端分离后,经常会修改接口,然后重新部署 ...
- centos7.6初始化python3.6环境
环境: CentOS Linux release 7.6.1810 (Core) Python3.6.x 01.检测yum源 wget -O /etc/yum.repos.d/epel.repo ht ...