【BZOJ 3672】【UOJ #7】【NOI 2014】购票
http://www.lydsy.com/JudgeOnline/problem.php?id=3672
链上的情况可以用斜率优化dp。树上用斜率优化dp时,单调队列的复杂度是均摊$O(n)$的,所以放到树上做“可持久化单调队列”复杂度是$O(n^2)$的,所以不能树上斜率优化。
这道题可以用树链剖分(时间复杂度$O(n\log^3n)$)或者点分治套cdq分治(时间复杂度$O(n\log^2n)$)。因为树链剖分感觉比较难写,而且每个节点用vector存单调队列,显得比较卡空间,而且时间复杂度多一个log,所以写了点分治。
对于一个点$i$,从i到根的路径上有$j$,$k$。假设$k$的深度比$j$小,且用$k$来更新$i$比$j$更优,得出式子($dis$为到根的距离):
$$\frac{f_j-f_k}{dis_j-dis_k}>p_i$$
对于每个点,把$dis$看成横坐标,$f$看成纵坐标,最优点一定在下凸壳上。
对于一棵树,求出分治重心,再对重心上方的子树进行分治,分治完后重心到该树的根上所有的点的$f$值都求好了,然后就用重心到根这条链上所有的点去更新重心子树中所有的点。
先对重心子树中所有的点(不包括重心)按“$l$值-到重心的距离”排序,保证用来更新“子树中的点”的“重心到根上的点”到重心的距离单调递增,这样拿单调栈来维护一个下凸壳来更新就可以了。
时间复杂度$O(n\log^2n)$。
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 200003;
int in() {
int k = 0, fh = 1; char c = getchar();
for(; c < '0' || c > '9'; c = getchar())
if (c == '-') fh = -1;
for(; c >= '0' && c <= '9'; c = getchar())
k = (k << 3) + (k << 1) + c - '0';
return k * fh;
}
ll inll() {
ll k = 0; int fh = 1; char c = getchar();
for(; c < '0' || c > '9'; c = getchar())
if (c == '-') fh = -1;
for(; c >= '0' && c <= '9'; c = getchar())
k = (k << 3) + (k << 1) + c - '0';
return k * fh;
} bool vis[N];
struct node {
int nxt, to; ll w;
node(int _nxt = 0, int _to = 0, ll _w = 0) : nxt(_nxt), to(_to), w(_w) {}
} E[N << 1];
int t, n, fa[N], Q[N], cnt = 0, sz[N], point[N];
ll f[N], fadis[N], p[N], q[N], l[N], longdis[N]; void ins(int u, int v, ll w) {E[++cnt] = node(point[u], v, w); point[u] = cnt;} int findrt(int x) {
int u, head = 0, tail = 1; Q[1] = x;
while (head != tail) {
u = Q[++head]; sz[u] = 1;
for(int i = point[u]; i; i = E[i].nxt)
if (!vis[E[i].to] && E[i].to != fa[u])
Q[++tail] = E[i].to;
}
for(int i = tail; i >= 1; --i) {
if ((sz[Q[i]] << 1) > tail) return Q[i];
sz[fa[Q[i]]] += sz[Q[i]];
}
} int tot, qu[N];
struct data {
ll dis, line; int id;
data(ll _dis = 0, ll _line = 0, int _id = 0) : dis(_dis), line(_line), id(_id) {}
bool operator < (const data &A) const {
return line < A.line;
}
} a[N]; double k_num(int x, int y) {
return 1.0 * (f[x] - f[y]) / (longdis[x] - longdis[y]);
} int find(int le, double k) {
int left = 0, right = le - 1, mid;
while (left < right) {
mid = (left + right) >> 1;
if (k_num(qu[mid], qu[mid + 1]) > k) left = mid + 1;
else right = mid;
}
if (left == le - 1 && k_num(qu[left], qu[le]) > k) return qu[le];
return qu[left];
} int cont = 0;
void cdq(int x) {
vis[x] = true;
int i, tmp, tail, head = 0, up = x; ll len = 0;
for(tmp = point[x]; tmp; tmp = E[tmp].nxt)
if (!vis[E[tmp].to] && E[tmp].to == fa[x]) {
while (!vis[fa[up]] && up != 1) up = fa[up];
cdq(findrt(up));
break;
} tot = 0;
for(i = point[x]; i; i = E[i].nxt)
if (!vis[E[i].to] && E[i].to != fa[x])
a[++tot] = data(fadis[E[i].to], l[E[i].to] - fadis[E[i].to], E[i].to); while (head != tot) {
++head;
for(i = point[a[head].id]; i; i = E[i].nxt)
if (!vis[E[i].to] && E[i].to != fa[a[head].id])
a[++tot] = data(fadis[E[i].to] + a[head].dis, l[E[i].to] - fadis[E[i].to] - a[head].dis, E[i].to);
} stable_sort(a + 1, a + tot + 1); tmp = x;
while (tmp != up) {
tmp = fa[tmp]; if (longdis[x] - longdis[tmp] > l[x]) break;
if (f[x] == -1) f[x] = f[tmp] + (longdis[x] - longdis[tmp]) * p[x] + q[x];
else f[x] = min(f[x], f[tmp] + (longdis[x] - longdis[tmp]) * p[x] + q[x]);
} tail = 0; tmp = x; qu[0] = x;
for(i = 1; i <= tot; ++i) {
if (a[i].line < 0) continue;
while (tmp != up && len + fadis[tmp] <= a[i].line) {
len += fadis[tmp];
tmp = fa[tmp];
while (tail && k_num(tmp, qu[tail]) > k_num(qu[tail], qu[tail - 1]))
--tail;
qu[++tail] = tmp;
}
head = find(tail, (double) p[a[i].id]);
if (f[a[i].id] == -1) f[a[i].id] = f[head] + (longdis[a[i].id] - longdis[head]) * p[a[i].id] + q[a[i].id];
else f[a[i].id] = min(f[a[i].id], f[head] + (longdis[a[i].id] - longdis[head]) * p[a[i].id] + q[a[i].id]);
} for(i = point[x]; i; i = E[i].nxt)
if (!vis[E[i].to] && E[i].to != fa[x])
cdq(findrt(E[i].to));
} int main() {
n = in(); t = in();
for(int i = 2; i <= n; ++i) {
fa[i] = in(); fadis[i] = inll();
ins(fa[i], i, fadis[i]);
ins(i, fa[i], fadis[i]);
p[i] = inll(); q[i] = inll(); l[i] = inll();
} memset(f, -1, sizeof(ll) * (n + 1));
f[1] = 0;
int u, head = 0, tail = 1;
Q[1] = 1; longdis[1] = 0;
while (head != tail) {
u = Q[++head];
for(int i = point[u]; i; i = E[i].nxt)
if (E[i].to != fa[u]) {
longdis[E[i].to] = longdis[u] + fadis[E[i].to];
Q[++tail] = E[i].to;
}
} cdq(findrt(1));
for(int i = 2; i <= n; ++i)
printf("%lld\n", f[i]);
return 0;
}
终于调完了,写完后有好多错QAQ
【BZOJ 3672】【UOJ #7】【NOI 2014】购票的更多相关文章
- [LOJ 2720][BZOJ 5417][UOJ 395][NOI 2018]你的名字
[LOJ 2720][BZOJ 5417][UOJ 395][NOI 2018]你的名字 题意 给定一个大串 \(S\) 以及 \(q\) 次询问, 每次询问给定一个串 \(T\) 和区间 \([l, ...
- BZOJ 3672 NOI 2014 购票
题面 Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树,每个城市 ...
- 【BZOJ 3669】【NOI 2014】魔法森林 LCT+枚举边
$LCT+枚举$ 复习一下$LCT$模板. 先以$Ai$为关键字$sort$,然后$Ai$从小到大枚举每条边,看能否构成环,构不成则加边,构成则判断,判断过了就切断$Bi$最大的边. 我的边是编号为$ ...
- 解题:NOI 2014 购票
题面 观察一下部分分,我们发现链上的部分分是这样一个DP: $dp[i]=min(dp[i],dp[j]+dis(i,j)*p[i]+q[i])(dis(i,j)<=lim[i]\&\& ...
- BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)
前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...
- [luogu P2375] [NOI 2014] 动物园
[luogu P2375] [NOI 2014] 动物园 题目描述 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅,只会卖萌向游客要吃的.为了整治动物园的不良风气,让动物们凭自己的真才实学向 ...
- 【BZOj 3670】【UOJ #5】【NOI 2014】动物园
http://www.lydsy.com/JudgeOnline/problem.php?id=3670 http://uoj.ac/problem/5 可以建出"KMP自动机"然 ...
- bzoj 3672: [Noi2014]购票 树链剖分+维护凸包
3672: [Noi2014]购票 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 480 Solved: 212[Submit][Status][D ...
- BZOJ 3672 购票
Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国\(n\)个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树,每个城市与 ...
随机推荐
- 这是啥-Cython语言简单介绍
Cython是一种既可以编写c又可以编写python的编程语言,他的目标是成为一个python语言的超集,为python提供高层次的.面向对象的.函数化.动态编程功能.不同于纯粹的python,它提供 ...
- USACO Sorting a Three-Valued Sequence
题目描述 排序是一种很频繁的计算任务.现在考虑最多只有三值的排序问题.一个实际的例子是,当我们给某项竞赛的优胜者按金银铜牌排序的时候.在这个任务中可能的值只有三种1,2和3.我们用交换的方法把他排成升 ...
- JSTL基础
是java中的一个定制标记库集 实现了jsp页面中的代码复用,基于标签库原理,重复率较高的代码块支持复用,提高效率 书写jsp页面时可读性更强 http://archive.apache.org/di ...
- 新闻发布系统<分页>
分页实现: 实现数据的分页显示,需要以下几个关键步骤: ①确定每页显示的总页数 ②计算显示的总页数 ③编写SQL语句 实现效果如图所示: 当点击下一页时,地址栏地址为?pageIndex=2 1.创建 ...
- Carcraft
魔兽登录系统 创建魔兽系统相关窗体: 登录窗体(frmLogin) 注册窗体(frmRegister) 主窗体 (frmMain) 实现魔兽登录系统: 登录的界面如下 实现思路: 1.创建一个 ...
- 手机开启HDR后拍照有什么不同?
转自http://www.leiphone.com/news/201406/hdr-pic.html HDR这词大家可能并不陌生,但大部分人只是听过而已,在脑子并没有太多的概念,可能只是简单的认为HD ...
- 穷举、迭代、以及while代替for循环的使用
for循环的穷举: 就是所有情况走一遍,使用if筛选出符合的情况. while循环分为2个格式 (1)先判断再做while(){}(2)不管对错,先做了在判断do{}whlie() 百鸡百钱的whil ...
- Eclipse c++代码提示,覆盖下面代码的问题。
今天在使用Eclipse自动提示时,会覆盖下面行的代码!!! 这个错误几乎不能忍,goolge无果. 手动尝试去掉,全部代码提示,终于找到解法办法,但是原因未知. 如下图:需要去掉 "Par ...
- 浅谈python web框架中的orm设计
看了一下廖雪峰的那个web框架,其实就是封装了web.py,请求使用异步并将aiomysql做为MySQL数据库提供了异步IO的驱动,前端部分则整合了jinja.其中最难的应该是orm部分了. 下面是 ...
- 关于IOS免证书真机安装的过程和问题
由于本人是边工作边转的IOS,所以一直都没怎么使用过免证书安装过程,通常都是公司申请的99美元的账号直接开发.但是前两天有个朋友需要在展会上用的Ipad上安装内网应用,申请一个苹果账号还要审核前后加起 ...