【NOI2014】【cdq点分治】【斜率优化】购票
2015-08-20 12:50
344 查看
0.先推出斜率优化的动归方程
1.找到当前分治的树结构的重心
2.将分成的子树中含有根节点那部分连重心一并分治
3.将其余子树的点拎出来,按照能走到的最小深度从大到小排序
4.对于每个点,将重心到分治结构的根节点路径上所有的点中能到达的那些点维护一个凸包 然后二分查找
5.对其余子树进行分治
时间复杂度O(nlog^2n)
1.找到当前分治的树结构的重心
2.将分成的子树中含有根节点那部分连重心一并分治
3.将其余子树的点拎出来,按照能走到的最小深度从大到小排序
4.对于每个点,将重心到分治结构的根节点路径上所有的点中能到达的那些点维护一个凸包 然后二分查找
5.对其余子树进行分治
时间复杂度O(nlog^2n)
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #define Rep(i, x, y) for (int i = x; i <= y; i ++) #define Dwn(i, x, y) for (int i = x; i >= y; i --) #define RepE(i, x) for(int i = pos[x]; i; i = g[i].nex) using namespace std; typedef long long LL; typedef long double DB; const int N = 500005; const LL inf = 1LL << 62; struct Edge { int y, nex; LL z; } g ; struct br { int n; LL z; } b ; struct CvH { LL x, y; } q ; int n, pos , sz, don , rt, siz, s , f0 , hd, tl, h , par , bz, up, qx, t; LL u , l , f , q0 , s1 , Ds , p ; void Init(int x, int y, LL z) { g[++ sz].y = y; g[sz].z = z, g[sz].nex = pos[x]; pos[x] = sz; } void Pred(int x) { RepE(i, x) { int y = g[i].y; if (y == par[x]) continue ; h[y] = h[x] + 1, par[y] = x, s1[y] = s1[x] + g[i].z; Pred(y); } } void Get(int x, int ft) { s[x] = 1, f0[x] = 0; RepE(i, x) { int y = g[i].y; if (don[y] || y == ft) continue ; Get(y, x), s[x] += s[y], f0[x] = max(f0[x], s[y]); } f0[x] = max(f0[x], siz - s[x]); if (f0[x] < f0[rt] || (f0[x] == f0[rt] && h[x] < h[rt])) rt = x; } void Dfs(int x, LL z) { if (l[x] >= z) b[++ bz] = (br) { x, l[x] - z }; RepE(i, x) { int y = g[i].y; if (y != par[x] && !don[y]) Dfs(y, z + g[i].z); } } void Find(int x, int ft) { if (h[x] < h[up]) up = x; RepE(i, x) { int y = g[i].y; if (y != ft && !don[y]) Find(y, x); } } bool Cmpb(br x, br y) { return x.z < y.z; } void Work(int x) { bool fl = 0; RepE(i, x) if (!don[ g[i].y ] && g[i].y != par[x]) don[ g[i].y ] = 2, fl = 1; qx = x, up = x, Find(x, 0); int up1 = up; if (!don[ par[x] ] && x != 1) { siz = s[ par[x] ] + 1, Get(par[x], rt = 0); Work(rt); } else don[x] = 1; bz = 0; RepE(i, x) { int y = g[i].y; if (don[y] == 2 && fl) don[y] = 0; else continue ; Dfs(y, g[i].z); } sort(b + 1, b + bz + 1, Cmpb); int k = x; LL t0 = 0; q[hd = tl = n] = (CvH) { s1[x], f[x] }; Rep(i, 1, bz) { while (t0 + Ds[k] <= b[i].z && k != up1) { t0 += Ds[k], k = par[k]; while (hd < tl && (q[hd + 1].y - q[hd].y) / (DB)(q[hd + 1].x - q[hd].x) <= (q[hd].y - f[k]) / (DB)(q[hd].x - s1[k])) hd ++; q[-- hd] = (CvH) { s1[k], f[k] }; } int l = hd, r = tl; while (l < r) { int u = (l + r + 1) >> 1; if ((q[u].y - q[u - 1].y) / (DB)(q[u].x - q[u - 1].x) < p[ b[i].n ]) l = u; else r = u - 1; } f[ b[i].n ] = min(f[ b[i].n ], q[l].y + (s1[ b[i].n ] - q[l].x) * p[ b[i].n ] + q0[ b[i].n ]); } RepE(i, x) { int y = g[i].y; if (don[y]) continue ; siz = s[y]; Get(y, rt = 0), Work(rt); } } int main() { scanf ("%d%d", &n, &t); Rep(i, 2, n) { int x; scanf ("%d%lld%lld%lld%lld", &x, &Ds[i], &p[i], &q0[i], &l[i]); Init(x, i, Ds[i]), Init(i, x, Ds[i]); f[i] = inf; } Pred(1); siz = n, f0[0] = n + 1; Get(1, rt = 0), Work(rt); Rep(i, 2, n) printf("%lld\n", f[i]); return 0; }
相关文章推荐
- IO
- 给圆角图片加阴影
- ds18b20驱动运行错误
- 【基础数论】十分钟学会计算欧拉函数
- Python的字符串操作和Unicode
- 黑马程序员——java基础语法
- ActiveMQ消息传送模型
- PAT《数据结构学习与实验指导》实验项目集 2-05. 求集合数据的均方差(15) C语言
- 继承关系类实例对象的非绑定关系方法调用
- 数学真头疼
- csv读入数据,用julia/matplotlib/pyplot 画矢量图导入word中
- android基于开源网络框架asychhttpclient,二次封装为通用网络请求组件
- 本地拦截genymotion或者Android模拟器的网络请求
- innodb 悲观锁,乐观锁
- 组件的使用(三)AutoCompleteTextView的使用
- socket编程中对sigpipe信号的处理
- Android开源项目第五篇——优秀个人和团体篇
- ELF文件格式以及装载过程
- 使用live delegate on解决js后装html故障问题
- Jquery