题面

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. poj2955:Brackets

    Brackets Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8716   Accepted: 4660 Descript ...

  2. loj2173 「FJOI2016」建筑师

    ref 真是道组合数学神题啊--第一次见第一类斯特林数-- #include <iostream> #include <cstdio> using namespace std; ...

  3. Quorum机制与NRW算法总结

    Quorum机制与NRW算法总结 1.Quorum机制 Quorum,原指为了处理事务.拥有做出决定的权力而必须出席的众议员或参议员的数量(一般指半数以上). 2.NRW算法 NRW算法是基于Quor ...

  4. 我给女朋友讲编程CSS系列(1) –添加CSS样式的3种方式及样式表的优先权

    如果说,原生态就是美,那么,我们就没有必要穿衣打扮. 网页是什么? 说白了,网页就是一堆[html标签]有序的搭配,让[CSS属性值]整整容,请[Javascript语言]处理一下事件. 一个人的整容 ...

  5. seajs引入jquery

    seajs 2.2.1在config文件中preload一次jquery,就可以在整个项目中使用jquery.如下: seajs.on('exec', function(module) { if (m ...

  6. json对象中根据主键判断是否有重复数据

    function funCheckRepeat() { var ids = $(gridId).jqGrid('getGridParam', 'selarrrow'); if (ids.length ...

  7. [DM8168]Linux下控制GPIO控制12864液晶屏(ST7565控制器)

    首先加载驱动模块,应用程序通过调用API实现GPIO控制功能. 驱动函数: /* * fileName: st7565_driver.c * just for LCD12864 driver * GP ...

  8. [oldboy-django][2深入django]mysql查询语句--原生sql

    # 增(一共有三种方式) # 插入单条记录 insert into t1(name,...) values('lzp',..); 注意一点:t1(name,...)必须包含所有非空列(除去自增列) # ...

  9. linux配置Hadoop伪分布安装模式

    1)关闭禁用防火墙: /etc/init.d/iptables status 会得到一系列信息,说明防火墙开着. /etc/rc.d/init.d/iptables stop 关闭防火墙 2)禁用SE ...

  10. 2018 ACM南京网络赛H题Set解题报告

    题目描述 给定\(n\)个数$a_i$,起初第\(i\)个数在第\(i\)个集合.有三种操作(共\(m\)次): 1 $u$ $v$ 将第$u$个数和第$v$个数所在集合合并 2 $u$ 将第$u$个 ...