解:转移方程写出来,发现是斜率优化。因为在树上,考虑CDQ分治 + 点分治的方法...

每次找到重心,然后先递归解决上面的子树。然后把上面子树的凸包搞出来,下面每个点在凸包上二分找最优决策。

重心自己不参与上面子树的递归,单独给下面转移。

注意这个东西斜率可能有负数,不能简单乘到不等式另一边。

二分的写法要注意。

每个点的转移还有个深度限制,所以要按照深度限制把询问(待转移的点)排序,然后一边动态加凸包一边二分回答询问。

 #include <bits/stdc++.h>

 typedef long long LL;
const int N = , INF = 0x3f3f3f3f;
const double eps = 1e-; struct Edge {
int nex, v;
LL len;
}edge[N << ]; int tp = ; int e[N], _n, root, small, siz[N], deep[N], fa[N], stk[N], top2, stk2[N], SMALL, n;
LL p[N], q[N], lim[N], d[N], f[N];
bool del[N]; inline bool cmp_l(const int &a, const int &b) {
return lim[a] < lim[b];
} template <class T> inline void Min(T &a, const T &b) {
a > b ? a = b : ;
return;
} inline void add(int x, int y, LL z) {
tp++;
edge[tp].v = y;
edge[tp].len = z;
edge[tp].nex = e[x];
e[x] = tp;
return;
} void DFS_1(int x, int f) {
deep[x] = deep[f] + ;
fa[x] = f;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == f) continue;
d[y] = d[x] + edge[i].len;
DFS_1(y, x);
}
return;
} void getroot(int x, int f) {
//printf("getroot : %d %d \n", x, f);
int large = ;
siz[x] = ;
Min(SMALL, deep[x]);
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(del[y] || y == f) continue;
getroot(y, x);
siz[x] += siz[y];
if(siz[y] > large) large = siz[y];
}
large = std::max(large, _n - siz[x]);
if(small > large) {
small = large;
root = x;
}
return;
} void DFS_2(int x, int f) {
stk2[++top2] = x;
//printf("DFS2 : %d \n", x);
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(del[y] || y == f) continue;
DFS_2(y, x);
}
return;
} inline bool check(int a, int b, int c) {
return (long double)(f[b] - f[a]) / (d[b] - d[a]) + eps > (long double)(f[c] - f[b]) / (d[c] - d[b]);
} void DFS_3(int x, int f) {
siz[x] = ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(del[y] || y == f) continue;
DFS_3(y, x);
siz[x] += siz[y];
}
return;
} void DFS_4(int x, int father, int rt) {
if(x != rt && d[rt] >= lim[x]) {
Min(f[x], f[rt] - p[x] * d[rt]);
/*if(x == 5) {
printf("f %d = %lld rt = %d \n", x, f[x], rt);
}*/
}
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == father || del[y]) continue;
DFS_4(y, x, rt);
}
return;
} void CDQ(int x) { //printf("CDQ : %d _n = %d \n", x, _n); if(_n == ) {
f[x] += p[x] * d[x] + q[x];
del[x] = ;
//printf("1 : f [ %d ] = %lld \n", x, f[x]);
return;
} SMALL = small = INF;
getroot(x, );
int tempsmall = SMALL;
x = root;
DFS_3(x, );
del[x] = ;
///
if(del[fa[x]]) {
f[x] += p[x] * d[x] + q[x]; //printf("2 : f [ %d ] = %lld \n", x, f[x]); DFS_4(x, , x);
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(del[y]) continue;
_n = siz[y];
CDQ(y);
}
return;
}
_n = siz[fa[x]];
CDQ(fa[x]); /**
while(top > 1 && check(stk[top - 1], stk[top], temp)) {
top--;
}
*/
top2 = ;
DFS_2(x, );
std::sort(stk2 + , stk2 + top2 + , cmp_l);
std::reverse(stk2 + , stk2 + top2 + );
int pos = fa[x], top = ;
//printf(" ----------------- x = %d fa[x] = %d \n", x, fa[x]);
/*printf("sort : ");
for(int i = 1; i <= top2; i++) {
printf("%d ", stk2[i]);
}
puts("");*/
for(int i = ; i <= top2; i++) {
int xx = stk2[i];
while(pos && deep[pos] >= tempsmall && d[pos] >= lim[xx]) {
/// insert p
while(top > && check(pos, stk[top], stk[top - ])) {
top--;
}
stk[++top] = pos;
//printf("insert pos = %d \n", pos);
pos = fa[pos];
}
if(!top) continue;
int l = , r = top;
//printf("l = %d r = top = %d \n", l, r);
while(l < r) {
int mid = (l + r) >> ;
//printf("mid = %d \n", mid);
if(l < mid && p[xx] > (long double)(f[stk[mid]] - f[stk[mid - ]]) / (d[stk[mid]] - d[stk[mid - ]])) {
r = mid - ;
}
else if(mid < r && p[xx] < (long double)(f[stk[mid + ]] - f[stk[mid]]) / (d[stk[mid +]] - d[stk[mid]])) {
//printf("-------------- %lld * %lld < %lld \n", p[xx], (d[stk[mid +1]] - d[stk[mid]]), (f[stk[mid + 1]] - f[stk[mid]]));
l = mid + ;
}
else {
r = mid;
break;
}
}
//printf("r = %d \n", r);
/// branch search OVER
//printf("Min %lld (%lld - %lld * %lld) \n", f[xx], f[stk[r]], p[xx], d[stk[r]]);
Min(f[xx], f[stk[r]] - p[xx] * d[stk[r]]);
//printf("%d -> %d f[%d] = %lld \n", stk[r], xx, xx, f[xx]);
} f[x] += p[x] * d[x] + q[x];
DFS_4(x, , x);
//printf("3 : f [ %d ] = %lld += %lld * %lld + %lld \n", x, f[x], p[x], d[x], q[x]); /// rest
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(del[y]) continue;
_n = siz[y];
CDQ(y);
}
return;
} int main() { freopen("in.in", "r", stdin);
//freopen("my.out", "w", stdout); memset(f, 0x3f, sizeof(f));
f[] = ;
int ttt; LL z;
scanf("%d%d", &n, &ttt);
for(int i = , x; i <= n; i++) {
scanf("%d%lld%lld%lld%lld", &x, &z, &p[i], &q[i], &lim[i]);
add(x, i, z); add(i, x, z);
}
/// input over
DFS_1(, );
for(int i = ; i <= n; i++) {
lim[i] = std::max(0ll, d[i] - lim[i]);
} //printf("OVER \n"); _n = n;
CDQ(); for(int i = ; i <= n; i++) {
printf("%lld\n", f[i]);
}
return ;
}

AC代码

LOJ#2249 购票的更多相关文章

  1. LOJ#2249 Luogu P2305「NOI2014」购票

    几乎肝了半个下午和整个晚上 斜率优化的模型好多啊... LOJ #2249 Luogu P2305 题意 给定一棵树,第$ i$个点如果离某个祖先$ x$的距离不超过$ L_i$,可以花费$ P_i· ...

  2. LOJ 2249: 洛谷 P2305: 「NOI2014」购票

    题目传送门:LOJ #2249. 题意简述: 有一棵以 \(1\) 号节点为根节点的带边权的树. 除了 \(1\) 号节点的所有节点上都有人需要坐车到达 \(1\) 号节点. 除了 \(1\) 号节点 ...

  3. LOJ 2249: 洛谷 P2305: bzoj 3672: 「NOI2014」购票

    题目传送门:LOJ #2249. 题意简述: 有一棵以 \(1\) 号节点为根节点的带边权的树. 除了 \(1\) 号节点的所有节点上都有人需要坐车到达 \(1\) 号节点. 除了 \(1\) 号节点 ...

  4. LibreOJ 题解汇总

    目录 #1. A + B Problem #2. Hello, World! #3. Copycat #4. Quine #7. Input Test #100. 矩阵乘法 #101. 最大流 #10 ...

  5. 【刷题笔记】火车购票-----java方案

    问题描述请实现一个铁路购票系统的简单座位分配算法,来处理一节车厢的座位分配. 假设一节车厢有20排.每一排5个座位.为方便起见,我们用1到100来给所有的座位编号,第一排是1到5号,第二排是6到10号 ...

  6. OC-《购票系统》

    来个命令行的购票系统 --1-- 需求分析 1.1 分析 1.2 功能分析 1.3 流程分析 --2-- 原型展示 2.1 界面原型 --3-- 系统设计 3.1 类设计 3.2 框架模块设计 --4 ...

  7. CCF 201612-2 火车购票 (暴力)

    问题描述 请实现一个铁路购票系统的简单座位分配算法,来处理一节车厢的座位分配. 假设一节车厢有20排.每一排5个座位.为方便起见,我们用1到100来给所有的座位编号,第一排是1到5号,第二排是6到10 ...

  8. zstu.4019.排队购票(多维dp)

    排队购票 Time Limit: 1 Sec  Memory Limit: 64 MB Submit: 1264  Solved: 808 Description 一常球赛开始前,售票工作正在进行中. ...

  9. [BZOJ3672][UOJ#7][NOI2014]购票

    [BZOJ3672][UOJ#7][NOI2014]购票 试题描述  今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会.       ...

随机推荐

  1. Storm原理

    zookeeper是对称结构

  2. linux audit审计(2)--audit启动

    参考:https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec- ...

  3. python 列表、元组、字典

    一.列表 [ ] 如下的列子都可以成为列表,c=[1,2,3,4,5,6],d=["abc", "张三",“李四”],e=[1,2,3,"abc&qu ...

  4. 集合之TreeSet(含JDK1.8源码分析)

    一.前言 前面分析了Set接口下的hashSet和linkedHashSet,下面接着来看treeSet,treeSet的底层实现是基于treeMap的. 四个关注点在treeSet上的答案 二.tr ...

  5. Yii的数值比较验证器

    该验证器比对两个特定输入值之间的关系 是否与 operator 属性所指定的相同. compareAttribute:用于与原属性相比对的属性名称. 当该验证器被用于验证某目标属性时, 该属性会默认为 ...

  6. Java面向对象之多态的静态和动态实现

    简单而言: 静态多态:即为重载,方法的重载 动态多态:即为重写/覆盖,方法的重写

  7. JavaScript之简易http接口测试工具网页版

    简易http接口测试工具网页版,支持get.post请求,支持json格式消息体,form表单暂不支持. httpClient.html <!DOCTYPE html> <html ...

  8. js4

    数组的解构赋值: 位置对象的解构赋值: 名称 // {}在解构赋值的时候,不能出现在一行的最前面,否则js解析器会把他当成一个代码块,加()({a, b} = obj),告诉他这个仅仅是一个解构语句 ...

  9. Jira的搭建

    一.环境准备 jira7.2的运行是依赖java环境的,也就是说需要安装jdk并且要是1.8以上版本,如下: java -version 除此之外,我们还需要为jira创建对应的数据库.用户名和密码, ...

  10. codeforces722B

    Verse Pattern CodeForces - 722B You are given a text consisting of n lines. Each line contains some ...