题面

Description

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

全国的城市构成了一棵以SZ市为根的有根树,每个城市与它的父亲用道路连接。为了方便起见,我们将全国的 n 个城市用 1 到 n 的整数编号。其中SZ市的编号为 1。对于除SZ市之外的任意一个城市 v,我们给出了它在这棵树上的父亲城市 fv 以及到父亲城市道路的长度 sv。

从城市 v 前往SZ市的方法为:选择城市 v 的一个祖先 a,支付购票的费用,乘坐交通工具到达 a。再选择城市 a 的一个祖先 b,支付费用并到达 b。以此类推,直至到达SZ市。

对于任意一个城市 v,我们会给出一个交通工具的距离限制 lv。对于城市 v 的祖先 a,只有当它们之间所有道路的总长度不超过 lv 时,从城市 v 才可以通过一次购票到达城市 a,否则不能通过一次购票到达。对于每个城市 v,我们还会给出两个非负整数 pv,qv 作为票价参数。若城市 v 到城市 a 所有道路的总长度为 d,那么从城市 v 到城市 a 购买的票价为 dpv+qv。

每个城市的OIer都希望自己到达SZ市时,用于购票的总资金最少。你的任务就是,告诉每个城市的OIer他们所花的最少资金是多少。

Input

第 1 行包含2个非负整数 n,t,分别表示城市的个数和数据类型(其意义将在后面提到)。输入文件的第 2 到 n 行,每行描述一个除SZ之外的城市。其中第 v 行包含 5 个非负整数 f_v,s_v,p_v,q_v,l_v,分别表示城市 v 的父亲城市,它到父亲城市道路的长度,票价的两个参数和距离限制。请注意:输入不包含编号为 1 的SZ市,第 2 行到第 n 行分别描述的是城市 2 到城市 n。

Output

输出包含 n-1 行,每行包含一个整数。其中第 v 行表示从城市 v+1 出发,到达SZ市最少的购票费用。同样请注意:输出不包含编号为 1 的SZ市。

Samples

input:

7 3
1 2 20 0 3
1 5 10 100 5
2 4 10 10 10
2 9 1 100 10
3 5 20 100 10
4 4 20 0 10

output:

40
150
70
149
300
150

HINT

对于所有测试数据,保证\(n \le 2 \times 10^5\), \(0≤p_v≤10^6\),\(0≤q_v≤10^{12}\),\(1≤f_v<v\);保证 \(0<s_v≤l_v≤2×10^{11}\),且任意城市到SZ市的总路程长度不超过 \(2×10^{11}\)。

至于数据类型什么的, 直接把它忽略掉, 整题AC即可.

Solution

做法貌似有很多, 但暂时来说会的就只有一种大暴力了:

首先我们不难写出一个斜率优化的式子:

\[\frac{f_j - f_k}{ dep_j - dep_k} < p_i
\]

考虑到不具有单调性, 我们要用二分的方法求出最优解; 又由于题目限制了我们可以取的\(j\)和\(k\)的范围, 考虑进行树链剖分病用线段树维护, 线段树上每个点维护其所包含区间的每个点组成的凸包, 在线段树上查找即可.

时间复杂度:

构建: \(O(n \log^2 n)\)

查询: \(O(n \log^3 n)\)


woc这个\(O(n \log^3 n)\)的方法还真TM能过啊, 当然仅限BZOJ... 这还是多亏了BZOJ的计时方法233

#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
#define vector std::vector
#define max std::max
#define min std::min
#define sort std::sort namespace Zeonfai
{
inline long long getInt()
{
long long a = 0, sgn = 1; char c;
while(! isdigit(c = getchar())) if(c == '-') sgn *= -1;
while(isdigit(c)) a = a * 10 + c - '0', c = getchar();
return a * sgn;
}
}
const int N = (int)2e5;
const long long INF = (long long)4e18;
int n;
struct point
{
long long x, y; int id;
inline point() {}
inline point(long long _x, long long _y, int _id) {x = _x; y = _y; id = _id;}
inline int operator <(const point a) const {return x < a.x;}
};
inline double slope(point a, point b)
{
if(a.x == b.x) return a.y > b.y ? - 1e30 : 1e30; else return (double)(a.y - b.y) / (a.x - b.x);
}
struct segmentTree
{
struct node
{
point *bck; int cnt;
inline node() {bck = NULL; cnt = 0;}
}nd[N << 2];
void insert(int u, int L, int R, point p, int pos)
{
if(L == R) {nd[u].bck = new point[nd[u].cnt = 1]; nd[u].bck[0] = p; return;}
if(pos <= L + R >> 1) insert(u << 1, L, L + R >> 1, p, pos); else insert(u << 1 | 1, (L + R >> 1) + 1, R, p, pos);
if(nd[u << 1].cnt && nd[u << 1 | 1].cnt)
{
static point bck[N], stk[N]; int cnt = 0, tp = 0;
for(int i = 0; i < nd[u << 1].cnt; ++ i) bck[cnt ++] = nd[u << 1].bck[i]; for(int i = 0; i < nd[u << 1 | 1].cnt; ++ i) bck[cnt ++] = nd[u << 1 | 1].bck[i];
sort(bck, bck + cnt);
for(int i = 0; i < cnt; ++ i)
{
while(tp >= 2 && slope(stk[tp - 1], stk[tp - 2]) > slope(bck[i], stk[tp - 1])) -- tp;
stk[tp ++] = bck[i];
}
nd[u].bck = new point[nd[u].cnt = tp];
for(int i = 0; i < tp; ++ i) nd[u].bck[i] = stk[i];
}
}
inline void insert(point p, int pos) {insert(1, 1, n, p, pos);}
vector<int> query(int u, int curL, int curR, int L, int R, long long slp)
{
vector<int> res; res.clear();
if(curL >= L && curR <= R)
{
L = 0, R = nd[u].cnt - 1; int ans;
while(L <= R)
{
int mid = L + R >> 1;
if(! mid || slope(nd[u].bck[mid - 1], nd[u].bck[mid]) < slp) ans = nd[u].bck[mid].id, L = mid + 1;
else R = mid - 1;
}
res.push_back(ans);
return res;
}
int mid = curL + curR >> 1;
if(L <= mid)
{
vector<int> tmp = query(u << 1, curL, mid, L, R, slp);
// for(auto id : tmp) res.push_back(id);
for(vector<int>::iterator id = tmp.begin(); id != tmp.end(); ++ id) res.push_back(*id);
tmp.clear();
}
if(R > mid)
{
vector<int> tmp = query(u << 1 | 1, mid + 1, curR, L, R, slp);
// for(auto id : tmp) res.push_back(id);
for(vector<int>::iterator id = tmp.begin(); id != tmp.end(); ++ id) res.push_back(*id);
tmp.clear();
}
return res;
}
inline vector<int> query(int L, int R, long long slp) {return query(1, 1, n, L, R, slp);}
}seg;
struct tree
{
struct node
{
vector<int> suc;
long long s, p, q, lim;
int pre, sz, hvy, tp, dfn;
long long dep, ans;
inline node() {suc.clear();}
}nd[N + 1];
void getSize(int u, int pre)
{
nd[u].sz = 1; nd[u].hvy = -1; nd[u].pre = pre; nd[u].dep = ~ pre ? nd[pre].dep + nd[u].s : 0;
for(auto v : nd[u].suc) {getSize(v, u); nd[u].sz += nd[v].sz; if(nd[u].hvy == -1 || nd[v].sz > nd[nd[u].hvy].sz) nd[u].hvy = v;}
// for(vector<int>::iterator v = nd[u].suc.begin(); v != nd[u].suc.end(); ++ v) {getSize(*v, u); nd[u].sz += nd[*v].sz; if(nd[u].hvy == -1 || nd[*v].sz > nd[nd[u].hvy].sz) nd[u].hvy = *v;}
}
int clk, idx[N + 1];
void work(int u, int tp)
{
nd[u].tp = tp; nd[u].dfn = ++ clk; idx[clk] = u; nd[u].ans = INF;
if(u != 1)
{
nd[u].ans = INF; int _u = nd[u].pre;
while(nd[nd[nd[_u].tp].pre].dep > nd[u].dep - nd[u].lim && nd[_u].tp != 1)
{
vector<int> res = seg.query(nd[nd[_u].tp].dfn, nd[_u].dfn, nd[u].p);
for(auto id : res) nd[u].ans = min(nd[u].ans, nd[id].ans + (nd[u].dep - nd[id].dep) * nd[u].p + nd[u].q);
// for(vector<int>::iterator id = res.begin(); id != res.end(); ++ id) nd[u].ans = min(nd[u].ans, nd[*id].ans + (nd[u].dep - nd[*id].dep) * nd[u].p + nd[u].q);
_u = nd[nd[_u].tp].pre; res.clear();
}
int L = nd[nd[_u].tp].dfn, R = nd[_u].dfn, tmp;
while(L <= R)
{
int mid = L + R >> 1;
if(nd[u].dep - nd[idx[mid]].dep <= nd[u].lim) {tmp = mid; R = mid - 1;} else L = mid + 1;
}
vector<int> res = seg.query(tmp, nd[_u].dfn, nd[u].p);
for(auto id : res) nd[u].ans = min(nd[u].ans, nd[id].ans + (nd[u].dep - nd[id].dep) * nd[u].p + nd[u].q);
// for(vector<int>::iterator id = res.begin(); id != res.end(); ++ id) nd[u].ans = min(nd[u].ans, nd[*id].ans + (nd[u].dep - nd[*id].dep) * nd[u].p + nd[u].q);
res.clear();
}
else nd[u].ans = 0;
seg.insert(point(nd[u].dep, nd[u].ans, u), nd[u].dfn);
if(~ nd[u].hvy) work(nd[u].hvy, tp);
for(auto v : nd[u].suc) if(v != nd[u].hvy) work(v, v);
// for(vector<int>::iterator v = nd[u].suc.begin(); v != nd[u].suc.end(); ++ v) if(*v != nd[u].hvy) work(*v, *v);
}
inline void decomposition() {getSize(1, -1); clk = 0; work(1, 1);}
}T;
int main()
{ #ifndef ONLINE_JUDGE freopen("BZOJ3672.in", "r", stdin);
freopen("BZOJ3672.out", "w", stdout); #endif using namespace Zeonfai;
n = getInt(); getInt();
for(int i = 2, pre; i <= n; ++ i) pre = getInt(), T.nd[pre].suc.push_back(i), T.nd[i].s = getInt(), T.nd[i].p = getInt(), T.nd[i].q = getInt(), T.nd[i].lim = getInt();
T.decomposition();
for(int i = 2; i <= n; ++ i) printf("%lld\n", T.nd[i].ans);
}

BZOJ 3672 NOI 2014 购票的更多相关文章

  1. 解题:NOI 2014 购票

    题面 观察一下部分分,我们发现链上的部分分是这样一个DP: $dp[i]=min(dp[i],dp[j]+dis(i,j)*p[i]+q[i])(dis(i,j)<=lim[i]\&\& ...

  2. BZOJ 3671 NOI 2014 随机数生成器 贪心

    题目大意:实在是太难说明了,自己看pdf吧.. 思路:优先依照它说明的方法处理数组,然后为了让数列中尽可能多的出现小的数字,所以1是必需要出现的,这样才干使整个数列的排序后字典序最小. 我们思考,假设 ...

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

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

  4. [luogu P2375] [NOI 2014] 动物园

    [luogu P2375] [NOI 2014] 动物园 题目描述 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅,只会卖萌向游客要吃的.为了整治动物园的不良风气,让动物们凭自己的真才实学向 ...

  5. [LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小园丁与老司机

    [LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小园丁与老司机 题意 给定平面上的 \(n\) 个整点 \((x_i,y_i)\), 一共有两个问题. 第一个问题是从原 ...

  6. [LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大会

    [LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大会 题意 给定一个长度为 \(n\) 的字符串 \(s\), 对于所有 \(r\in[1,n]\) 求出 \(s\ ...

  7. [LOJ 2718][UOJ 393][BZOJ 5415][NOI 2018]归程

    [LOJ 2718][UOJ 393][BZOJ 5415][NOI 2018]归程 题意 给定一张无向图, 每条边有一个距离和一个高度. 再给定 \(q\) 组可能在线的询问, 每组询问给定一个点 ...

  8. [LOJ 2083][UOJ 219][BZOJ 4650][NOI 2016]优秀的拆分

    [LOJ 2083][UOJ 219][BZOJ 4650][NOI 2016]优秀的拆分 题意 给定一个字符串 \(S\), 求有多少种将 \(S\) 的子串拆分为形如 AABB 的拆分方案 \(| ...

  9. [LOJ 2721][UOJ 396][BZOJ 5418][NOI 2018]屠龙勇士

    [LOJ 2721][UOJ 396][BZOJ 5418][NOI 2018]屠龙勇士 题意 题面好啰嗦啊直接粘LOJ题面好了 小 D 最近在网上发现了一款小游戏.游戏的规则如下: 游戏的目标是按照 ...

随机推荐

  1. va_list

    void Log( const TCHAR *pszFormat, ... ) { TCHAR buf[] ; va_list arglist ; try { _tcscpy_s ( buf, , _ ...

  2. loj2043 「CQOI2016」K 远点对

    k-d tree 裸题------ #include <algorithm> #include <iostream> #include <cstdio> using ...

  3. OpenStack之虚机冷迁移代码简析

    OpenStack之虚机冷迁移代码简析 前不久我们看了openstack的热迁移代码,并进行了简单的分析.真的,很简单的分析.现在天气凉了,为了应时令,再简析下虚机冷迁移的代码. 还是老样子,前端的H ...

  4. Python-S9-Day87——admin的使用

    01 admin的使用1 02 admin的使用2 03 admin的使用3 04 url方法的使用 05 单例模式 06 admin源码之注册功能 07 admin源码之url设计 08 admin ...

  5. 用nc+简单bat/vbs脚本+winrar制作迷你远控后门

    前言 某大佬某天和我聊起了nc,并且提到了nc正反向shell这个概念. 我对nc之前的了解程度仅局限于:可以侦听TCP/UDP端口,发起对应的连接. 真正的远控还没实践过,所以决定写个小后门试一试. ...

  6. java基础-流

    大致列一下这个周末需要学习的内容 1 容器 2 线程 3 流 (本节内容) 一. 流 按方向-------------输入流输出流 按处理数据单位-----字节流字符流 按功能------------ ...

  7. OOP的三大特性------封装、继承、多态

    封装 1.<1>类背后隐藏的思想是数据抽象和封装 <2>信息隐藏,隐藏对象的实现细节,不让外部直接访问到 将数据成员和成员函数一起包装到一个单元里,单元以类的形式实现 < ...

  8. linux下telnet安装与使用

    现在管理linux基本都用crt.xshell或者putty,已经没什么人用telnet,因为后续需要讲zabbix免客户端监控只telnet,通过telnet来监控服务器性能. yum安装telne ...

  9. hihoCoder 第136周 优化延迟(二分答案+手写堆)

    题目1 : 优化延迟 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Ho编写了一个处理数据包的程序.程序的输入是一个包含N个数据包的序列.每个数据包根据其重要程度不同 ...

  10. 蔬菜(vegetable)

    蔬菜(vegetable) 题目描述 题目背景:您使用脚本刷出了上题游戏 998244353 关的最高分 (最优解),心满意足的准备点继续学习,忽然一条弹窗弹了出来:你想明白活着的意义吗?你想真正的. ...