【题解】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][ ...
随机推荐
- MySQL在同一表格里把字段值(value)给另一字段(name)
在最近的窗帘项目中,我需要增加新的计价方法,其中就有一个是在后台输入价格的: 数据表: 购买页面 点击提交订单 那么我要算出有遮光衬布物品的价格,就必须知道我在后台设置的价格是多少 所以上代码: $i ...
- maven-认识
1.认识maven maven是强大的项目构建工具,也是依赖管理工具 使用maven前提是安装JDK maven非常重要配置文件:setting.xml 3.maven工程 maven工程的约束: 主 ...
- Hadoop(14)-MapReduce框架原理-切片机制
1.FileInputFormat切片机制 切片机制 比如一个文件夹下有5个小文件,切片时会切5个片,而不是一个片 案例分析 2.FileInputFormat切片大小的参数配置 源码中计算切片大小的 ...
- python3 练习题100例 (二十三)与7相关的数
与7相关的数:如果一个正整数,它能被7整除或者它的十进制表示法中某个位数上的数字为7,则称之为与7相关的数.(10分) 题目内容: 现在我们给定一个正整数n(n<1000),求所有小于等于n的与 ...
- Java学习笔记八:Java的流程控制语句之循环语句
Java的流程控制语句之循环语句 一:Java循环语句之while: 生活中,有些时候为了完成任务,需要重复的进行某些动作.如参加 10000 米长跑,需要绕 400 米的赛道反复的跑 25 圈.在 ...
- unity独立游戏开发日记2018/09/27
今天优化了下昨天的代码,并且添加了树木和其他资源的生成.还修复了接近石头后,挖掘图标不出现的bug.目前可以在unity中稳定60-70fps. 详看文章:https://www.cnblogs.co ...
- python入门——Anaconda安装
初学Python,可以选择python原始的IDE,但原始的IDE在使用过程中需要自己安装各种包,个人觉得初学者不需要将时间花在这些上面,而是应该直接学习python程序,这些比较杂的事情可以在以后的 ...
- React 省市区三级联动
省市区所对应的数据来自:http://www.zgguan.com/zsfx/jsjc/6541.html react中的代码是: export default class AddReceive ex ...
- 汇编实验14:访问CMOS RAM
汇编实验14:访问CMOS RAM 任务 编程,以“年/月/日 时:分:秒”的格式,显示当前的日期,时间. 预备知识 CMOS存储当前时间的信息:年.月.日.时.分.秒.这六个信息的长度均为1个字节, ...
- Django学习之天气调查实例(2):显示数据表数据
数据表数据添加后,如添加3条用户信息,分别为“aaa”.“bbb”.“ccc”,现在通过代码的方式显示数据表中的数据. 1.在website项目文件夹中创建 userload.py文件,并且写如下代码 ...