【题解】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][ ...
随机推荐
- JQuery中使用FormData异步提交数据和提交文件
web中数据提交事件是常常发生的,但是大多数情况下我们不希望使用html中的form表单提交,因为form表单提交会中断当前浏览器的操作并且会调到另一个地址(即使这个地址是当前页面),并且会重复加载一 ...
- springmvc的类型转换器converter
这个convter类型转换是器做什么用的? 他是做类型转换的,或者数据格式化处理.可以把数据在送到controller之前做处理.变成你想要的格式或者类型.方便我们更好的使用. 比如说你从前台传过来一 ...
- Lavavel5.5源代码 - 并发数控制
app('redis')->connection('default')->funnel('key000') // 每个资源最大锁定10秒自动过期,只有60个资源(并发),在3秒内获取不到锁 ...
- YUM工具使用
一.yum命令概述: 1.简介: yum命令时在Fedora和RedHat以及SUSE中基于rpm的软件包管理器,它可以使系统管理人员交互和自动化地更细与管理RPM软件包,能够从指定的服务器自动下载R ...
- re模块(详解正则)
re模块 imort re 1.\w \W print(re.findall('\w','ab 12\+- _*&')) #\w 匹配字母 数字 及下划线 执行结果:['a', 'b', '1 ...
- go学习笔记-程序测试
程序测试 测试是一个可重复的过程,它验证某个东西是否按预期工作.一般通过 go test 进行测试,步骤如下 首先,是我们的文件名.Go 要求所有的测试都在以 _test.go 结尾的文件中.这使得我 ...
- windows 安装 .net core 环境
windows 安装 环境说明 window10系统 .net core 1.0.1 visual studio code 安装 .net core Windows系统下安装软件基本上属于傻瓜式安装, ...
- Codeforces 845 C Two TVs
参考:https://blog.csdn.net/xjh_shin/article/details/77491693 #include <iostream> #include <cs ...
- 如何在Moodle中显示PPT课件
Moodle中目前是不直接支持PPT的,所以需要曲线救国: 1.安装 iSpring Free 8版本,免费版,其实是一个PPT的插件,在PPT的工具栏中有显示. 2.打开PPT后,直接在该工具中进行 ...
- 【Keras案例学习】 多层感知机做手写字符分类(mnist_mlp )
from __future__ import print_function # 导入numpy库, numpy是一个常用的科学计算库,优化矩阵的运算 import numpy as np np.ran ...