实际上是一个不完美算法……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购票的更多相关文章

  1. 题解 [NOI2014]购票

    题目传送门 题目大意 有一个 \(n\) 个点的树,每个点有三个值 \(p_u,q_u,l_u\) ,现在可以从 \(u\) 走到点 \(v\) 当且仅当 \(v\) 是 \(u\) 的祖先并且 \( ...

  2. [BZOJ3672][UOJ#7][NOI2014]购票

    [BZOJ3672][UOJ#7][NOI2014]购票 试题描述  今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会.       ...

  3. 【BZOJ 3672】 3672: [Noi2014]购票 (CDQ分治+点分治+斜率优化)**

    3672: [Noi2014]购票 Description  今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会.        全国 ...

  4. 【BZOJ3672】[Noi2014]购票 树分治+斜率优化

    [BZOJ3672][Noi2014]购票 Description  今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会.       ...

  5. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

  6. $NOI2014$ 购票(斜率优化 点分治)

    \(NOI2014\)购票 哇终于可以碰电脑了赶快切些火题找找感觉. 拿到这道题的时候发现简单的斜率优化推一推可以秒掉平方做法,然后一条链也可以做. 然后呢... 卧槽这个在一棵树上怎么办啊. 大力\ ...

  7. bzoj 3672: [Noi2014]购票 树链剖分+维护凸包

    3672: [Noi2014]购票 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 480  Solved: 212[Submit][Status][D ...

  8. BZOJ 3672: [Noi2014]购票( 树链剖分 + 线段树 + 凸包 )

    s弄成前缀和(到根), dp(i) = min(dp(j) + (s(i)-s(j))*p(i)+q(i)). 链的情况大家都会做...就是用栈维护个下凸包, 插入时暴力弹栈, 查询时就在凸包上二分/ ...

  9. bzoj千题计划251:bzoj3672: [Noi2014]购票

    http://www.lydsy.com/JudgeOnline/problem.php?id=3672 法一:线段树维护可持久化单调队列维护凸包 斜率优化DP 设dp[i] 表示i号点到根节点的最少 ...

  10. [BZOJ3672][Noi2014]购票 斜率优化+点分治+cdq分治

    3672: [Noi2014]购票 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 1749  Solved: 885[Submit][Status][ ...

随机推荐

  1. pygame小游戏之坦克大战

    以前在学校的时候无聊的学了会pygame.看了大概一周的教学视频,做出来个坦克大战的小游戏 Python3.5  pycharm import pygame,sys,time from random ...

  2. python3 练习题100例 (二十七)列表元素改写

    题目内容: 输入一个列表alist,要求列表中的每个元素都为正整数且不超过10: 将列表中的奇数变为它的平方,偶数除以2后打印新的列表(新的列表中所有元素仍都为整数). 可以使用以下实现列表alist ...

  3. stm32+lwip(一):使用STM32CubeMX生成项目

    我是卓波,很高兴你来看我的博客. 系列文章: stm32+lwip(一):使用STM32CubeMX生成项目 stm32+lwip(二):UDP测试 stm32+lwip(三):TCP测试 stm32 ...

  4. 20145202 《Java程序设计》实验五实验报告

    一.实验内容 1.用书上的TCP代码,实现服务器与客户端. 2.客户端与服务器连接 3.客户端中输入明文,利用DES算法加密,DES的秘钥用RSA公钥密码中服务器的公钥加密,计算明文的Hash函数值, ...

  5. [Windows]_[C/C++]_[如何调试子进程]

    场景 1.VC++ 的程序A在启动程序C时, 如果需要调试程序C的话一般有两种, 一种是通过菜单 调试->附加到进程的方式来调试程序, 缺点就是这个进程必须先启动, 但是一启动的话有可能就执行了 ...

  6. Sphinx与coreseek

    Sphinx : 高性能SQL全文检索引擎 分类 编程技术 Sphinx是一款基于SQL的高性能全文检索引擎,Sphinx的性能在众多全文检索引擎中也是数一数二的,利用Sphinx,我们可以完成比数据 ...

  7. [转]Visual Studio 项目类型 GUID 清单

    转自:https://www.codeproject.com/Reference/720512/List-of-Visual-Studio-Project-Type-GUIDs Complete li ...

  8. Android开发免费类库和工具集合

    用于Android开发的免费类库和工具集合,按目录分类. Action Bars ActionBarSherlock Extended ActionBar FadingActionBar GlassA ...

  9. 『AngularJS』创建 Service

    创建服务 Angular提供了几种有用的服务,对于所有的应用来说,你将会发现这些服务对于创建你自己的服务是有用处的.为了创建自己的服务,你应该从通过一个模块(module)注册一个服务工厂方法开始(可 ...

  10. springmvc基础篇—通过注解的方式去配置项目

    学习了通过xml方式去配置项目后,当然要掌握更简单更灵活的注解方式哟,这是官方推荐使用的方式. 一.修改配置文件,建议大家直接使用我的配置文件 <?xml version="1.0&q ...