解:转移方程写出来,发现是斜率优化。因为在树上,考虑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. Eclipse导入工程后出现中文乱码

    Eclipse之所以会出现乱码问题是因为eclipse编辑器选择的编码规则是可变的.一般默认都是UTF-8或者GBK,当从外部导入的一个工程时,如果该工程的编码方式与eclipse中设置的编码方式不同 ...

  2. Python 基础知识----流程控制

    判断语句 循环语句 嵌套

  3. vue 思維導圖

    vue概念:vue是一個輕量級的javascript庫:是一種漸進式的框架:vue可以實現數據視圖雙向綁定. vue基礎語法:實例化.條件.循環 vue重頭戲:動畫.組件.過濾.ajax.自定義組件. ...

  4. HTTP协议 - 使用php模拟get/post请求

    首先 有个疑问, 是不是只有浏览器才能发送http 请求? 答案肯定是错的,第一篇就说了,http是由请求行,请求头,请求主体三个部分组成,那么我们可不可以用代码来模拟一下get和post请求呢: 首 ...

  5. 线程同步Volatile与Synchronized(一)

    volatile 一.volatile修饰的变量具有内存可见性 volatile是变量修饰符,其修饰的变量具有内存可见性. 可见性也就是说一旦某个线程修改了该被volatile修饰的变量,它会保证修改 ...

  6. Announcing Windows Template Studio in UWP

    今天,我们很高兴地宣布您的文件→新的通用Windows平台应用程序在Visual Studio - Windows模板工作室中的下一个演变.Windows Template Studio在开发人员调查 ...

  7. hdu-2222(ac自动机模板)

    题意:给你一个长度为n的单词表,一个文本串,问你这个文本串中出现了单词表中多少个单词: 解题思路:ac自动机的模板题,可以直接当模板用: 代码: #include<iostream> #i ...

  8. ElasticSearch查询 第四篇:匹配查询(Match)

    <ElasticSearch查询>目录导航: ElasticSearch查询 第一篇:搜索API ElasticSearch查询 第二篇:文档更新 ElasticSearch查询 第三篇: ...

  9. Linux下tomcat中多项目配置druid报错的问题

    这里有多种方法,推荐修改tomcat配置,即在启动JVM配置中设置如下: -Ddruid.registerToSysProperty=true 详解参见该博: https://blog.csdn.ne ...

  10. BZOJ2275[Coci2010]HRPA——斐波那契博弈

    题目描述 N个石子,A和B轮流取,A先.每个人每次最少取一个,最多不超过上一个人的个数的2倍.取到最后一个石子的人胜出,如果A要有必胜策略,第一次他至少要取多少个. 输入 第一行给出数字N,N< ...