「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}\)自动机 ...
随机推荐
- 【bzoj题解】2186 莎拉公主的困惑
题目传送门. 题意:求\([1,n!]\)中与\(m!\)互质的数的个数,对质数\(R\)取模,\(n\geq m\). 答案应该等于\(\frac{n!}{m!}\phi(m!)=\frac{n!} ...
- 【codeforces】【比赛题解】#868 CF Round #438 (Div.1+Div.2)
这次是Div.1+Div.2,所以有7题. 因为时间较早,而且正好赶上训练,所以机房开黑做. 然而我们都只做了3题.:(. 链接. [A]声控解锁 题意: Arkady的宠物狗Mu-mu有一只手机.它 ...
- Wood Cut
Given n pieces of wood with length L[i] (integer array). Cut them into small pieces to guarantee you ...
- Vagrant 无法校验手动下载的 Homestead Box 版本
起因 4年前电脑,配置不太好了,现有的 Homestead 运行起来太吃内存.在修改了 Homestead.yaml 文件里 memory 选项的内存配置为 1024 后,应用最新配置重启失败. 索性 ...
- bzoj 1607 Patting Heads 轻拍牛头
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1607 题解: 题目似乎出错,应为“同时拍打所有所持纸条上的数字能被此牛所持纸条上的数字整除 ...
- linux终端操作快捷键
终端操作快捷键: 新建家目录下终端窗口:Ctrl+Alt+t在当期当前路径下新建终端窗口:Ctrl+Shift+n退出终端窗口:Ctrl+Shift+q 多个终端窗口之间相互切换:Tab+Alt 终端 ...
- Flask:abort()函数
Windows 10家庭中文版,Python 3.6.4,Flask 1.0.2 abort()函数用于提前退出(Google翻译abort)一个请求,并用指定的错误码返回. 函数原型如下: flas ...
- 线性表应用--Josephus问题的解法(Python 版)
线性表应用 --Josephus问题的解法(Python 版) Josephus问题描述:假设有n个人围坐一圈,现在要求从第k个人开始报数,报到第m个数的人退出.然后从下一个人开始继续报数并按照相同的 ...
- python基础--json,pickle和shelve模块
一.JSON &pickle 用于序列化的两个模块 json,用于字符串 和 python数据类型间进行转换 字符串必须是双引号,不能是单引号 pickle,用于python特有的类型 和 ...
- Ibatis.Net 各类的作用说明学习(三)
Ibatis中,加载.分析配置及映射文件是在创建SqlMapper实例的时候进行的,另外对数据库的操作,也是在SqlMapper实例上调用方法来完成.创建SqlMapper的实例的方式是: ISqlM ...