【题解】NOI2014购票
实际上是一个不完美算法……cogs上面A不掉(爆栈啦)。感谢机房大佬PPY的指点,现在也写出来供大家参考参考,理解起来应该是比较简单的一种。
我们首先get出斜率优化方程:
\(dp[v] = dis[v] * p[u] - dis[u] * p[u] - q[u] + dp[u] \left ( 0 <= dis[u] - dis[v] <= lim[u] \right )\)
那么 \(y = dp[v]; x = dis[v]; k = p[u]; \) 我们所要做的就是维护一个下凸包以维护最小的b值。现在有两个本题的难点:首先,转移到\(u\)点的\(v\)点必须是u的祖先,且两者之间相距的距离在一定的限制范围之内。如何满足?我们想到,既然需要维护一定范围内的一个凸包,那么我们可以借助数据结构来完成。线段树可以做到:一个线段树上的节点代表从(l ~ r)这段区间内的节点所构成的凸包,那么任何一个区间都可以由线段树上上的节点凑成,取每一个中间的最大值即可。
所以我们的线段树所维护的即为一条链上的节点(按深度递增编号)。但还有一个问题没有解决:当我们将一个节点加入凸包的时候我们会为了维护凸包的凸性而弹出一些节点(包括在这个节点的子树都处理完毕之后,该节点自身也要离开凸包,因为它不再属于链上的节点)。那么在处理完之后,我们就希望能够将线段树还原回访问它之前的样子——先想想普通的维护做法:从单调队列的队尾不断弹出元素,直到凸包合法为止。仔细考虑这个过程,我们可以将操作简化为:找到最后一个弹出的元素(a), 意思就是弹出元素(a)后加入当前元素(b)(用(b)替换(a)),再更新队尾指针的指向。所以我们只需要对于每一个节点都维护一下它所弹出的节点&修改的队尾位置就可以了,最后再还原回去。
以下代码——注意INF大大大大大……就这里调了我三个小时,直到我发现了修改INF读到的值竟然不一样的惊天大秘密……Σ(っ°Д°;)っ
#include <bits/stdc++.h>
using namespace std;
#define maxn 200050
#define lgmaxn 25
#define INF 99999999999999999LL
#define ll long long
#define db double
int n, t;
ll P[maxn], Q[maxn], dp[maxn], dis[maxn], len[maxn];
ll X[maxn], Y[maxn], last = ;
int q[maxn * ], dep[maxn], degree[maxn];
int cnp = , head[maxn], maxx; struct tree
{
int head, tail;
}T[maxn * ]; struct edge
{
int to, last, co;
}E[maxn]; struct node
{
int pret, id;
}S[maxn][lgmaxn]; void add(int u, int v, int w)
{
E[cnp].to = v, E[cnp].last = head[u];
E[cnp].co = w, head[u] = cnp ++;
} db Get_S(int a, int b)
{
ll x1 = X[a], y1 = Y[a], x2 = X[b], y2 = Y[b];
return (db) (y1 - y2) / (db) (x1 - x2);
} void Build(int p, int l, int r)
{
int size = (r - l + );
T[p].head = last + , T[p].tail = last;
last += size; if(l == r) return;
int mid = (l + r) >> ;
Build(p << , l, mid);
Build(p << | , mid + , r);
} void update(int p, int l, int r, int k, int tot, node *a)
{
int h = T[p].head, &t = T[p].tail, pret = T[p].tail;
h += ;
while(h <= t)
{
int mid = (h + t) >> ;
if(Get_S(q[mid - ], q[mid]) >= Get_S(q[mid], k)) t = mid - ;
else h = mid + ;
}
t ++; a[++ tot] = (node) { pret, q[t] };
q[t] = k;
if(l == r) return;
int mid = (l + r) >> ;
if(k <= mid) update(p << , l, mid, k, tot, a);
else update(p << | , mid + , r, k, tot, a);
} int check(int h, int t, int k)
{
int l = h, r = t - , ans = -;
if(l <= r + ) ans = l;
while(l <= r)
{
int mid = (l + r) >> ;
if(Get_S(q[mid], q[mid + ]) <= (db) k) ans = mid + , l = mid + ;
else r = mid - ;
}
return q[ans];
} ll query(int p, ll lim, ll K)
{
int t = T[p].tail, h = T[p].head;
if(dis[q[t]] < lim) return INF;
if(dis[q[h]] >= INF) return INF;
if(dis[q[h]] >= lim && dis[q[t]] < INF)
{
ll x = check(T[p].head, T[p].tail, K);
x = Y[x] - K * X[x];
return x;
}
else return min(query(p << , lim, K), query(p << | , lim, K));
} void rebound(int p, int l, int r, int k, int tot, node *a)
{
q[T[p].tail] = a[tot].id;
T[p].tail = a[tot].pret;
int mid = (r + l) >> ;
if(l == r) return;
if(k <= mid) rebound(p << , l, mid, k, ++ tot, a);
else rebound(p << | , mid + , r, k, ++ tot, a);
} void DFS(int u, int fa, ll co)
{
dep[u] = dep[fa] + ;
ll tem = dis[dep[u] - ] + co;
if(u != ) dp[u] = query((ll) , max((ll) , tem - len[u]), P[u]) + tem * P[u] + Q[u];
else dp[u] = ;
if(degree[u])
{
dis[dep[u]] = u == ? : tem; X[dep[u]] = dis[dep[u]], Y[dep[u]] = dp[u];
update(, , n, dep[u], , S[dep[u]]);
for(int i = head[u]; i; i = E[i].last)
{
int v = E[i].to;
DFS(v, u, E[i].co);
}
rebound(, , n, dep[u], , S[dep[u]]);
X[dep[u]] = Y[dep[u]] = dis[dep[u]] = INF;
}
} int main()
{
scanf("%d%d", &n, &t);
for(int i = ; i <= n; i ++) X[i] = INF, Y[i] = INF, dis[i] = INF;
for(int i = ; i <= n; i ++)
{
int f, x;
scanf("%d%d", &f, &x);
scanf("%lld%lld%lld", &P[i], &Q[i], &len[i]);
add(f, i, x);
degree[f] ++;
}
Build(, , n);
DFS(, , );
for(int i = ; i <= n; i ++)
printf("%lld\n", dp[i]);
return ;
}
【题解】NOI2014购票的更多相关文章
- 题解 [NOI2014]购票
题目传送门 题目大意 有一个 \(n\) 个点的树,每个点有三个值 \(p_u,q_u,l_u\) ,现在可以从 \(u\) 走到点 \(v\) 当且仅当 \(v\) 是 \(u\) 的祖先并且 \( ...
- [BZOJ3672][UOJ#7][NOI2014]购票
[BZOJ3672][UOJ#7][NOI2014]购票 试题描述 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. ...
- 【BZOJ 3672】 3672: [Noi2014]购票 (CDQ分治+点分治+斜率优化)**
3672: [Noi2014]购票 Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国 ...
- 【BZOJ3672】[Noi2014]购票 树分治+斜率优化
[BZOJ3672][Noi2014]购票 Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. ...
- BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)
前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...
- $NOI2014$ 购票(斜率优化 点分治)
\(NOI2014\)购票 哇终于可以碰电脑了赶快切些火题找找感觉. 拿到这道题的时候发现简单的斜率优化推一推可以秒掉平方做法,然后一条链也可以做. 然后呢... 卧槽这个在一棵树上怎么办啊. 大力\ ...
- bzoj 3672: [Noi2014]购票 树链剖分+维护凸包
3672: [Noi2014]购票 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 480 Solved: 212[Submit][Status][D ...
- BZOJ 3672: [Noi2014]购票( 树链剖分 + 线段树 + 凸包 )
s弄成前缀和(到根), dp(i) = min(dp(j) + (s(i)-s(j))*p(i)+q(i)). 链的情况大家都会做...就是用栈维护个下凸包, 插入时暴力弹栈, 查询时就在凸包上二分/ ...
- bzoj千题计划251:bzoj3672: [Noi2014]购票
http://www.lydsy.com/JudgeOnline/problem.php?id=3672 法一:线段树维护可持久化单调队列维护凸包 斜率优化DP 设dp[i] 表示i号点到根节点的最少 ...
- [BZOJ3672][Noi2014]购票 斜率优化+点分治+cdq分治
3672: [Noi2014]购票 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 1749 Solved: 885[Submit][Status][ ...
随机推荐
- EpiiAdmin 开源的php交互性管理后台框架, 让复杂的交互变得更简单!Phper快速搭建交互性平台的开发框架,基于Thinkphp5.1+Adminlte3.0+Require.js。
EpiiAdmin EpiiAdmin php开源交互性管理后台框架,基于Thinkphp5.1+Adminlte3.0+Require.js, 让复杂的交互变得更简单!Phper快速搭建交互性平台的 ...
- Spark知识点
1.Spark架构 分布式spark应用中的组件 在分布式环境下,Spark集群采用的是主/从结构.在一个Spark集群中,有一个节点负责中央协调,调度各个分布式工作节点.这个中央协调节点被称为驱动器 ...
- java服务端项目开发规范
更新内容 2015-03-13 (请先更新svn的mybatis.xml.BaseMapper.java.Pager.java文件) 加入测试类规范 加入事物控制规范 加入mapper接口规则 ...
- python应用:异常处理
Python的错误异常在大部分IDE编辑器中则可以直接显示出来,便于开发人员的调试及修改工作,对初学者也比较友好. Python中包含错误和异常两种情况,错误主要是常见的语法错误SyntaxError ...
- Python自动化运维——文件与目录差异对比
Infi-chu: http://www.cnblogs.com/Infi-chu/ 模块:filecmp 安装:Python版本大于等于2.3默认自带 功能:实现文件.目录.遍历子目录的差异 常用方 ...
- CPU计算密集型和IO密集型
CPU计算密集型和IO密集型 第一种任务的类型是计算密集型任务,其特点是要进行大量的计算,消耗CPU资源,比如计算圆周率.对视频进行高清解码等等,全靠CPU的运算能力.这种计算密集型任务虽然也可以用多 ...
- 5.hbase表新增数据同步之add_peer
一.前提主从集群之间能互相通讯: 二.在cluster1上(源集群): 1.查看集群已开启的peers hbase(main):011:0> list_peers PEER_ID CLUSTE ...
- onenet基础通信套件返回+CIS ERROR: 50的问题解决
1. 场景分析,主要问题就是有些操作返回+CIS ERROR: 50 2. 看了一下在AT+MIPLOBSERVERSP这个指令里面是没有返回+CIS ERROR: 50的错误类型的,所以应该是在解析 ...
- JavaScript函数constructor的作用,意义
前几天写了一片 如何用正确的姿势编写jQuery插件 有朋友拍砖,指正.再此谢谢! 讨论:指定函数的constructor作用到底是什么? 我们一般写jQuery插件的时候是这样的: //构造函数 f ...
- ubuntu安装显卡驱动和cuda
NVIDIA-linux.run安装后,会出现登录页面循环,解决办法是在运行命令后加入-no-opengl-files 打开nvidia x server Settings软件,显示:You do n ...