题面

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. MVC中Spring.net 对基类控制器无效 过滤器控制器无效

    比如现在我又一个BaseController作为基类控制器,用于过滤权限.登录判断等作用,其它控制由原本的继承Controller,改为继承BaseController.然后BaseControlle ...

  2. HDU 5739 Fantasia 双连通分量 树形DP

    题意: 给出一个无向图,每个顶点有一个权值\(w\),一个连通分量的权值为各个顶点的权值的乘积,一个图的权值为所有连通分量权值之和. 设删除顶点\(i\)后的图\(G_i\)的权值为\(z_i\),求 ...

  3. SpringMVC基本概念

    DispatcherServlet:MVC的前端控制器,浏览器用户的请求经过DispatcherServlet的分发,到达合适的controller,生产业务数据所需要的model,model通过Di ...

  4. privoxy+ss5实现 HTTP 代理协议转socks5代理

    一.系统准备资源         二.ss5安装部署 1.SOCK5代理服务器部署环境准备 IP:10.0.0.100 官网: http://ss5.sourceforge.net/ 下载 yum - ...

  5. R语言分析朝阳医院数据

    R语言分析朝阳医院数据 本次实践通过分析朝阳医院2016年销售数据,得出“月均消费次数”.“月均消费金额”.“客单价”.“消费趋势”等结果,并据此作出可视化图形. 一.读取数据: library(op ...

  6. python - 接口自动化测试 - basic_data - 基础数据参数化方法封装

    # -*- coding:utf-8 -*- ''' @project: ApiAutoTest @author: Jimmy @file: basic_data.py @ide: PyCharm C ...

  7. HTML中使用JavaScript

    1.script中使用src引入外部js.注意:不能是<script />,必须是<script></script> 2.使用link引入外部js 3.使用scri ...

  8. @inerface的11条规范写法

    总结一些interface声明时的规范,相关宏的介绍,定义方法时有用的修饰符,编写注释的规范,最终写出一个合格的头文件. 1.读写权限 1.1实例变量的@public,@protected,@priv ...

  9. 【Luogu】P2488工作安排(费用流)

    题目链接 这题……费用流即可……(哇啊要被打死辣) 然而我printf("%d")爆零四次 好的心如死灰 #include<cstdio> #include<cs ...

  10. 网络流 24 题汇总(LOJ 上只有 22 题???)

    太裸的我就不放代码了...(黑体字序号的题表示值得注意) 1.搭配飞行员 [LOJ#6000] 二分图最大匹配. 2.太空飞行计划 [LOJ#6001] 最小割常规套路.输出方案.(注:这题换行符要用 ...