LOJ#2249 购票

解:转移方程写出来,发现是斜率优化。因为在树上,考虑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 购票的更多相关文章
- LOJ#2249 Luogu P2305「NOI2014」购票
几乎肝了半个下午和整个晚上 斜率优化的模型好多啊... LOJ #2249 Luogu P2305 题意 给定一棵树,第$ i$个点如果离某个祖先$ x$的距离不超过$ L_i$,可以花费$ P_i· ...
- LOJ 2249: 洛谷 P2305: 「NOI2014」购票
题目传送门:LOJ #2249. 题意简述: 有一棵以 \(1\) 号节点为根节点的带边权的树. 除了 \(1\) 号节点的所有节点上都有人需要坐车到达 \(1\) 号节点. 除了 \(1\) 号节点 ...
- LOJ 2249: 洛谷 P2305: bzoj 3672: 「NOI2014」购票
题目传送门:LOJ #2249. 题意简述: 有一棵以 \(1\) 号节点为根节点的带边权的树. 除了 \(1\) 号节点的所有节点上都有人需要坐车到达 \(1\) 号节点. 除了 \(1\) 号节点 ...
- LibreOJ 题解汇总
目录 #1. A + B Problem #2. Hello, World! #3. Copycat #4. Quine #7. Input Test #100. 矩阵乘法 #101. 最大流 #10 ...
- 【刷题笔记】火车购票-----java方案
问题描述请实现一个铁路购票系统的简单座位分配算法,来处理一节车厢的座位分配. 假设一节车厢有20排.每一排5个座位.为方便起见,我们用1到100来给所有的座位编号,第一排是1到5号,第二排是6到10号 ...
- OC-《购票系统》
来个命令行的购票系统 --1-- 需求分析 1.1 分析 1.2 功能分析 1.3 流程分析 --2-- 原型展示 2.1 界面原型 --3-- 系统设计 3.1 类设计 3.2 框架模块设计 --4 ...
- CCF 201612-2 火车购票 (暴力)
问题描述 请实现一个铁路购票系统的简单座位分配算法,来处理一节车厢的座位分配. 假设一节车厢有20排.每一排5个座位.为方便起见,我们用1到100来给所有的座位编号,第一排是1到5号,第二排是6到10 ...
- zstu.4019.排队购票(多维dp)
排队购票 Time Limit: 1 Sec Memory Limit: 64 MB Submit: 1264 Solved: 808 Description 一常球赛开始前,售票工作正在进行中. ...
- [BZOJ3672][UOJ#7][NOI2014]购票
[BZOJ3672][UOJ#7][NOI2014]购票 试题描述 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. ...
随机推荐
- Oracle增删改查sql语句
--创建表空间 create tablespace waterboss datafile 'd:\waterboss.dbf' size 100m autoextend on next 10m --创 ...
- 本地上传项目到github
https://www.cnblogs.com/rosej/p/6056467.html(copy)
- PHP的爬虫框架
Beanbun PHPSpider PHPQuery QueryList PHPCrawer Snoopy
- ajax查看详细返回信息
查看详细成功返回信息: success : function(data, textStatus, jqXHR) { console.log(data); console.log(textStatus) ...
- centOS 开机自启动自己的脚本
centOS 开机自启动自己的脚本 1. 自己脚本 myservice 如下: #!/bin/bash # chkconfig: # description: myservice .... echo ...
- c++创建文件夹以及子文件夹
#ifdef WIN32 #include <io.h> #include <direct.h> #else #include <unistd.h> #includ ...
- Java 设计模式 ------ 模板设计模式
模板设计模式主要来源于生活中有一些事情是有模板可以遵循的.举两个生活中的例子,如泡茶和泡咖啡,看一看. 泡茶有以下四个步骤: 1, 烧开水; 2 把茶放到水杯中; 3,倒入开水; 4, 加糖. 泡 ...
- 英特尔DRM内核驱动程序默认启用PSR2省电功能
导读 英特尔DRM/KMS内核驱动程序很快就会启用PSR2面板自刷新功能,以便在英特尔支持的超极本/笔记本电脑上实现更多节能. 一段时间以来,英特尔的Direct Rendering Manager驱 ...
- 如何在Ubuntu 18.04上安装Django
Django是一个免费的开源高级Python Web框架,旨在帮助开发人员构建安全,可扩展和可维护的Web应用程序. 根据您的需要,有不同的方法来安装Django.它可以使用pip在系统范围内安装或在 ...
- Cmder使用ls中文显示乱码解决方案
操作系统:Windows 7 旗舰版 Cmder:1.3.2 默认配置不支持使用ls显示中文命名的文件列表. 解决方法: 按下Win+Alt+P打开设置. 在StartUp - Environment ...