「NOI2014」购票
「NOI2014」购票
解题思路
先列出 \(dp\) 式子并稍微转化一下
dp[u]=\min(dp[v]+dis[v]\times p[u]) + p[u]\times dis[u]+q[u] \\
\]
假设有 \(dis(v2)< dis(v1)\) 且 \(p(u)\) 在 \(v2\) 的取值比 \(v1\) 优,可以得到斜率式
\dfrac{dp(v2) -dp(v1)}{dis(v2)-dis(v1)}\geq p(u)
\]
利用 \(cdq\) 的思想对有根树进行点分治,每次计算分治中心 \(H\) 到其祖先的一条链对其它联通块的贡献,维护一个凸包在凸包上二分即可,还挺好写的,复杂度 \(\mathcal O(n\log^2n)\) 。
code
/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf ((ll)(1e18))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
#define int ll
const int N = 2000005;
vector<int> g[N];
int dis[N], dep[N], lim[N], dp[N], d[N], Q[N], p[N], pa[N];
int A[N], sz[N], vis[N], pq[N], q[N], n, mn, rt, all, cnt;
inline double slope(int x, int y){
return (double) (dp[y] - dp[x]) / (double) (dis[y] - dis[x]);
}
inline bool cmp(int x, int y){
return dis[x] - lim[x] > dis[y] - lim[y];
}
inline void update(int x, int y){
dp[x] = min(dp[y] + (dis[x] - dis[y]) * p[x] + q[x], dp[x]);
}
inline void prework(int u, int fa){
pa[u] = fa, dep[u] = dep[fa] + 1, dis[u] = dis[fa] + d[u];
for(int i = 0; i < (int) g[u].size(); i++)
if(g[u][i] != fa) prework(g[u][i], u);
}
inline void getsize(int u, int fa){
int mson = 0; sz[u] = 1;
for(int i = 0; i < (int) g[u].size(); i++){
int v = g[u][i];
if(vis[v] || v == fa) continue;
getsize(v, u), sz[u] += sz[v];
if(sz[v] > mson) mson = sz[v];
}
mson = max(mson, all - sz[u]);
if(mson < mn) mn = mson, rt = u;
}
inline void dfs(int u, int fa){
A[++cnt] = u;
for(int i = 0; i < (int) g[u].size(); i++)
if(!vis[g[u][i]] && g[u][i] != fa) dfs(g[u][i], u);
}
inline void divtree(int u, int top){
vis[u] = 1; int lst = all;
for(int i = 0; i < (int) g[u].size(); i++){
int v = g[u][i];
if(!vis[v] && v == pa[u]){
mn = all = sz[v] > sz[u] ? lst - sz[u] : sz[v];
getsize(v, u), divtree(rt, top);
}
}
for(int s = pa[u]; s != pa[top]; s = pa[s])
if(dis[u] - dis[s] <= lim[u]) update(u, s);
cnt = 0;
for(int i = 0; i < (int) g[u].size(); i++){
int v = g[u][i];
if(!vis[v]) dfs(v, u);
}
sort(A + 1, A + cnt + 1, cmp);
int t = 0; int s = u;
for(int i = 1; i <= cnt; i++){
while(s != pa[top] && dis[A[i]] - lim[A[i]] <= dis[s]){
while(t > 1 && slope(Q[t-1], Q[t]) <= slope(Q[t-1], s)) t--;
Q[++t] = s, s = pa[s];
}
int l = 1, r = t - 1, res = 1;
while(l <= r){
int mid = (l + r) >> 1;
if(slope(Q[mid], Q[mid+1]) >= (double) p[A[i]])
res = l = mid + 1;
else r = mid - 1;
}
if(res <= t) update(A[i], Q[res]);
}
for(int i = 0; i < (int) g[u].size(); i++){
int v = g[u][i];
if(vis[v]) continue;
mn = all = sz[v] > sz[u] ? lst - sz[u] : sz[v];
getsize(v, u), divtree(rt, v);
}
}
signed main(){
read(n); int type; read(type);
for(int i = 2, x; i <= n; i++){
read(x), read(d[i]), read(p[i]);
read(q[i]), read(lim[i]), dp[i] = inf;
g[x].push_back(i), g[i].push_back(x);
}
prework(1, 0);
mn = all = n, getsize(1, 0), divtree(rt, 1);
for(int i = 2; i <= n; i++) printf("%lld\n", dp[i]);
return 0;
}
「NOI2014」购票的更多相关文章
- 「NOI2014」购票 解题报告
「NOI2014」购票 写完了后发现写的做法是假的...然后居然过了,然后就懒得管正解了. 发现需要维护凸包,动态加点,询问区间,强制在线 可以二进制分组搞,然后你发现在树上需要资瓷撤回,然后暴力撤回 ...
- 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\) 号节点 ...
- 【LOJ】#2244. 「NOI2014」起床困难综合症
题解 写水题放松一下心情 二进制有个很好的性质是每一位是独立的,我们按位贪心,先看这一位能不能填1,然后看看如果这一位填0那么运算后最后这一位是不是1,是的话就退出,然后看看这一位如果填1最后是1这一 ...
- 「NOI2014」魔法森林
题目链接 戳我 \(Solution\) 两个变量,emm...不好搞啊. 于是我们可以按照\(A\)排序.然后动态加边,因为\(A\)是越来越大,所以不需要管他,只要使得\(1\)~\(n\)的路径 ...
- LOJ#2244. 「NOI2014」起床困难综合症
$n \leq 1e5$个位运算操作,$m \le 2^{30}$,问$0-m$中谁进行完所有操作值最大,输出这个最大值. cfA题难度?当送分题就不管了 and相当于几个位取0,or相当于几个位取1 ...
- 「NOI2014」动物园
link : https://loj.ac/problem/2246 水水KMP #include<bits/stdc++.h> #define ll long long #define ...
- LG2375/LOJ2246 「NOI2014」动物园 KMP改造
问题描述 LG2375 LOJ2246 题解 看了题解,需要回看,需要继续通过本题深入理解KMP. 为了将 \(\mathrm{KMP}\) 和只插入了一个模式串的\(\mathrm{AC}\)自动机 ...
随机推荐
- 17、enum简介
enum简介 在日常开发中可能有一些东西是固定的,比如一年只有4个季节,春夏秋冬.我们可以自己定义一个类里面存放这4个季节.在jdk5之后,引入了枚举(enum)的概念,可以通过enum去定义这四个季 ...
- JS设计模式——7.工厂模式(概念)
工厂模式 本章讨论两种工厂模式: 简单工厂模式 使用一个类(通常是一个单体)来生成实例. 使用场景:假设你想开几个自行车商店(创建自行车实例,组装它,清洗它,出售它),每个店都有几种型号的自行车出售. ...
- ubuntu安装Android Studio开发环境
1.下载 https://developer.android.com/studio/ 2.解压文件,将文件夹copy到/opt/ 3.进入/opt/android-studio/bin,运行./stu ...
- glut glew区别
GLEW是一个跨平台的C++扩展库,基于OpenGL图形接口.使用OpenGL的朋友都知道,window目前只支持OpenGL1.1的涵数,但 OpenGL现在都发展到2.0以上了,要使用这些Open ...
- java7与java8中计算两个日期间隔多少年多少月多少天的实现方式
最近工作中碰到个新需求,计算每个员工入职公司的时长,要求形式为多少年多少月多少天形式,某个值为0就跳过不显示,因为前段时间学习过java8新特性,对于这个需求,java8的新时间日期API可以直接解决 ...
- Oracle Certified Java Programmer 经典题目分析(二)
...接上篇 what is reserved(保留) words in java? A. run B. default C. implement D. import Java 关键字列表 (依字母排 ...
- Vue起步
Vue起步 Vue.js是什么 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式javascript框架.与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用. ...
- HOG目标检测
用HOG进行行人检测时,需要用训练好的支持向量机来对图片进行分类,在opencv中,支持向量机已经训练好,但自己来训练支持向量机才能更好的体会这一过程. 参考:http://blog.csdn.net ...
- sql server 约束 查找
--1.主键约束 SELECT tab.name AS [表名], idx.name AS [主键名称], col.name AS [主键列名] FROM sys.indexes idx JOIN s ...
- Kubernetes 概述和搭建(多节点)
一.Kubernetes整体概述和架构 Kubernetes是什么 Kubernetes是一个轻便的和可扩展的开源平台,用于管理容器化应用和服务.通过Kubernetes能够进行应用的自动化部署和扩缩 ...