您的位置:首页 > 其它

【NOI2014】【cdq点分治】【斜率优化】购票

2015-08-20 12:50 344 查看
0.先推出斜率优化的动归方程

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: