s弄成前缀和(到根), dp(i) = min(dp(j) + (s(i)-s(j))*p(i)+q(i)). 链的情况大家都会做...就是用栈维护个下凸包, 插入时暴力弹栈, 查询时就在凸包上二分/三分. 扩展到树上的话, 就先树链剖分, 然后就变成链上的情况了, 线段树每个结点处理出对应的区间的凸包. 对于x, 用Root到fa[x]这段路径来更新x. 我们知道1段路径会剖成 ≤ log N 段, 然后每段(区间)只会影响log N个线段树结点, 加上每次O(log N)三分/二分, 时间复杂度是O(N log^3 N). 常数很小, 可以过. 空间复杂度是O(N log N)

-------------------------------------------------------------------------

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
 
using namespace std;
 
typedef long long ll;
 
const int maxn = 200009;
const double eps = 1e-9;
 
int N, L, R, Top, n, T;
int fa[maxn], p[maxn], seq[maxn * 20];
int top[maxn], sz[maxn], dep[maxn], ch[maxn], Id[maxn], _Id[maxn];
ll q[maxn], d[maxn], len[maxn], ans[maxn];
 
template<class T>
inline void Min(T &x, T t) {
if(t < x) x = t;
}
 
template<class T>
inline T& read(T &x) {
char c = getchar(); x = 0;
while(!isdigit(c)) c = getchar();
for(; isdigit(c); c = getchar()) x = x * 10 + c - '0';
return x;
}
 
struct edge {
int t;
edge* n;
} E[maxn], *Pt = E, *H[maxn];
 
inline void AddEdge(int u, int v) {
Pt->t = v, Pt->n = H[u], H[u] = Pt++;
}
 
void dfs(int x) {
sz[x] = 1, ch[x] = -1;
if(~fa[x]) d[x] += d[fa[x]];
for(edge* e = H[x]; e; e = e->n) {
dep[e->t] = dep[x] + 1;
dfs(e->t);
sz[x] += sz[e->t];
if(!~ch[x] || sz[e->t] > sz[ch[x]]) ch[x] = e->t;
}
}
 
void DFS(int x) {
Id[x] = ++n;
top[_Id[n] = x] = Top;
if(~ch[x]) DFS(ch[x]);
for(edge* e = H[x]; e; e = e->n)
if(e->t != ch[x]) DFS(Top = e->t);
}
 
void Init() {
read(N);
read(n);
for(int i = 1; i < N; i++) {
AddEdge(fa[i] = read(fa[i]) - 1, i);
read(d[i]), read(p[i]), read(q[i]), read(len[i]);
}
fa[0] = -1;
dfs(dep[0] = 0);
DFS(n = Top = 0);
}
 
bool Cmp(const int &l, const int &r) {
return dep[l] < dep[r];
}
 
struct Node {
Node *lc, *rc;
int l, r;
} pool[maxn << 1], *pt = pool, *Root;
 
void Build(Node* t, int l, int r) {
t->l = n, t->r = n - 1;
n += r - l + 1;
if(l != r) {
int m = (l + r) >> 1;
Build(t->lc = pt++, l, m);
Build(t->rc = pt++, m + 1, r);
}
}
 
inline ll calc(int x) {
return ans[seq[x]] - d[seq[x]] * p[T];
}
 
void Query(Node* t, int l, int r) {
if(L <= l && r <= R && d[T] - d[_Id[r]] > len[T]) return;
if(L <= l && r <= R && d[T] - d[_Id[l]] <= len[T]) {
l = t->l, r = t->r;
while(l <= r) {
int lth = (r - l) / 3;
int m1 = l + lth, m2 = r - lth;
ll c1 = calc(m1), c2 = calc(m2);
if(c1 < c2)
r = m2 - 1, Min(ans[T], c1);
else
l = m1 + 1, Min(ans[T], c2);
}
} else {
int m = (l + r) >> 1;
if(L <= m) Query(t->lc, l, m);
if(m < R) Query(t->rc, m + 1, r);
}
}
 
void QUERY(int x, int y) {
for(; top[x] != top[y]; x = fa[top[x]]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
L = Id[top[x]], R = Id[x];
Query(Root, 1, N);
}
if(dep[x] < dep[y]) swap(x, y);
L = Id[y], R = Id[x];
Query(Root, 1, N);
}
 
inline bool chk(int a, int b, int c) {
if(d[b] == d[c]) return false;
return (double) (ans[b] - ans[a]) / (d[b] - d[a]) - (double) (ans[c] - ans[b]) / (d[c] - d[b]) > eps;
}
 
void Modify(Node* t, int l, int r) {
while(t->r > t->l && chk(seq[t->r - 1], seq[t->r], T)) t->r--;
while(t->r >= t->l && d[seq[t->r]] == d[T] && ans[seq[t->r]] >= ans[T]) t->r--;
if(t->r < t->l || d[seq[t->r]] != d[T]) seq[++t->r] = T;
if(l != r) {
int m = (l + r) >> 1;
Id[T] <= m ? Modify(t->lc, l, m) : Modify(t->rc, m + 1, r);
}
}
 
void Work() {
n = 0;
Build(Root = pt++, 1, N);
ans[T = 0] = 0;
Modify(Root, 1, N);
for(T = 1; T < N; T++) {
ans[T] = 1LL << 62;
QUERY(0, fa[T]);
ans[T] += d[T] * p[T] + q[T];
Modify(Root, 1, N);
}
for(int i = 1; i < N; i++)
printf("%lld\n", ans[i]);
}
 
int main() {
Init();
Work();
return 0;
}

-------------------------------------------------------------------------

3672: [Noi2014]购票

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 669  Solved: 315
[Submit][Status][Discuss]

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市。

Sample 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

Sample Output

40
150
70
149
300
150

HINT

对于所有测试数据,保证 0≤pv≤106,0≤qv≤1012,1≤fv<v;保证 0<sv≤lv≤2×1011,且任意城市到SZ市的总路程长度不超过 2×1011

输入的 t 表示数据类型,0≤t<4,其中:

当 t=0 或 2 时,对输入的所有城市 v,都有 fv=v-1,即所有城市构成一个以SZ市为终点的链;

当 t=0 或 1 时,对输入的所有城市 v,都有 lv=2×1011,即没有移动的距离限制,每个城市都能到达它的所有祖先;

当 t=3 时,数据没有特殊性质。

n=2×10^5

Source

BZOJ 3672: [Noi2014]购票( 树链剖分 + 线段树 + 凸包 )的更多相关文章

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

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

  2. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

  3. BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)

    BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...

  4. bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2852  Solved: 1668[Submit][Sta ...

  5. bzoj 2157: 旅游【树链剖分+线段树】

    裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...

  6. BZOJ 3589 动态树 (树链剖分+线段树)

    前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...

  7. 【bzoj2402】陶陶的难题II 分数规划+树链剖分+线段树+STL-vector+凸包+二分

    题目描述 输入 第一行包含一个正整数N,表示树中结点的个数.第二行包含N个正实数,第i个数表示xi (1<=xi<=10^5).第三行包含N个正实数,第i个数表示yi (1<=yi& ...

  8. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  9. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  10. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

随机推荐

  1. android 实现自己定义状态栏通知(Status Notification)

    在android项目的开发中,有时为了实现和用户更好的交互,在通知栏这一小小的旮旯里,我们通常须要将内容丰富起来,这个时候我们就须要去实现自己定义的通知栏,比如以下360或者网易的样式: 首先我们要了 ...

  2. NGUI 3.5过程(三)Button button

    写在前面:     本文将创建一个主要的Button.而且编写脚本,响应点击事件. 欢迎大家纠错.拍砖.原创非常辛苦,如有转载,请注明出处. Button -- button 在NGUI 3.5 里, ...

  3. JS获取客户端IP地址、MAC和主机名七种方法

    一.使用JS获取客户端IP的几个方法方法一(只针对IE且客户端的IE允许AcitiveX运行,通过平台:XP,SERVER03,2000).获取客户端IP代码:<HTML><HEAD ...

  4. Sublime 学习记录(五) Sublime 其他插件(个人喜好)

    (一)  JSFormat 安装 :命令面板 pci 回车 JSFormat 回车 功能 : javascript的代码格式化插件 简介 : 很多网站的JS代码都进行了压缩,一行式的甚至混淆压缩,这让 ...

  5. Android 开源控件系列_2

    FileBrowserView 一个强大的文件选择控件.界面比较漂亮,使用也很简单.特点:可以自定义UI:支持复制.剪切.删除.移动文件:可以用在Fragment.ativity.DialogFrag ...

  6. python----脚本文件的头部写法。

    #!/usr/bin/python #这里主要是为了指明python脚本解释器的路径. #!coding:utf-8#这个是为了告知python脚本文件解释器,此脚本的字符集. import sys ...

  7. Struts2的Stack Context和ValueStack

    1.提到Struts2的传值功能时,经常会见到Stack Context和ValueStack等概念,那么它们到底是什么,有什么作用呢. ValueStack(值栈):Struts2将OGNL上下文设 ...

  8. jQuery背景跟随鼠标移动的网页导航

    首页 PSD模板 CSS模板 特效插件 源码下载 酷站欣赏 建站资源 建站教程 心境之旅 在线留言 设为首页 加入收藏 我要投稿 联系站长 Search     首页 PSD模板 CSS模板 特效插件 ...

  9. puppet svn集成

    puppet svn集成

  10. linux 学习之九、Linux 磁盘与文件系统管理(1)

    原文地址:http://vbird.dic.ksu.edu.tw/linux_basic/0230filesystem.php#filesys 查看文件系统参数命令 dumpe2fs 盘符地址 例: ...