BZOJ - 3672: [Noi2014]购票

3672: [Noi2014]购票

记$dp_u$为从$1$到$u$的最小花费,$dis_u$为从$1$到$u$的距离。

可以列出转移方程,$dp_v=\min\{dp_u+dis(u,v)p_v+q_v\} \; dis(u,v) \leqslant l_v = \min\{dp_u-p_vdis_u\} + d_vp_v + q_v$

这样就得到了一个从$1$向下递推的$O(N^2)$的算法。

如果对于$v$,$i$比$j$更优秀,那么,

$dp_i-p_vdis_i < dp_j-p_vdis_j$

$dp_i-dp_j<p_v(dis_i-dis_j)$

设$d_i<d_j$

$\frac{dp_i-dp_j}{dis_i-dis_j}>p_v$

于是就可以斜率优化了。$p_v$不单调,咱要在凸壳上二分斜率。

为了处理$l$的限制,咱把点处理的顺序改变一下,按照最远能到的祖先排序,就不用每次都重构凸壳了。

 1 #include<algorithm>
 2 #include<bitset>
 3 #include<vector>
 4 #include<cstdio>
 5 #include<iostream>
 6 #define pb push_back
 7 using namespace std;
 8 typedef long long ll;
 9 typedef double db;
10 inline char nc() {
11     static char b[1<<16],*s=b,*t=b;
12     return s==t&&(t=(s=b)+fread(b,1,1<<16,stdin),s==t)?-1:*s++;
13 }
14 template < class T >
15 inline void read(T &x) {
16     char b = nc(); x = 0;
17     for (; !isdigit(b); b = nc());
18     for (; isdigit(b); b = nc()) x = x * 10 + b - '0';
19 }
20 const int N = 200005;
21 struct Edge {int v; ll w;};
22 int n, nnn;
23 int p[N], fa[N], sz[N], mx[N], top, stk[N];
24 ll s[N], l[N], q[N], dp[N], dis[N];
25 vector < Edge > g[N];
26 bitset < N > vis;
27 double sp[N]; template < class T > inline void gmin(T &x, T y) {if (x > y) x = y;} template < class T > inline void gmax(T &x, T y) {if (x < y) x = y;}
28 inline void ae(int u, int v, ll w) {
29     g[u].pb((Edge){v, w});
30 }
31 void getR(int u, int size, int &R) {
32     sz[u] = 1; mx[u] = 0;
33     for (int v, i = 0; i < g[u].size(); ++i) if (!vis[v = g[u][i].v]) {
34         getR(v, size, R); sz[u] += sz[v]; gmax(mx[u], sz[v]);
35     } gmax(mx[u], size - sz[u]);
36     if (mx[u] < mx[R] && sz[u] > 1) R = u;
37 }
38 int c[N], C;
39 void dfs(int u) {
40     c[++C] = u;
41     for (int v, i = 0; i < g[u].size(); ++i)
42         if (!vis[v = g[u][i].v]) dfs(v);
43 }
44 inline bool cmp(int a, int b) {
45     return dis[a] - l[a] > dis[b] - l[b];    
46 }
47 inline db slope(int a, int b) {
48     return db(dp[a] - dp[b]) / db(dis[a] - dis[b]);
49 }
50 inline void insert(int i) {
51     db s = (N == top ? 1e10 : slope(stk[top], i));
52     while (N - top >= 2 && sp[top] < s) s = slope(stk[++top], i);
53     stk[--top] = i; sp[top] = s; 
54 }
55 inline int query(db x) {
56     return stk[(lower_bound(sp + top, sp + N, x) - sp)];
57 }
58 void solve(int u, int S) {
59     if (S == 1) return;
60     int v, r = 0, i, j; getR(u, S, r);
61     for (i = 0; i < g[r].size(); ++i)
62         vis[g[r][i].v] = 1;
63     solve(u, S - sz[r] + 1);
64     C = 0; for (int i = 0; i < g[r].size(); ++i) dfs(g[r][i].v);
65     sort(c + 1, c + 1 + C, cmp);
66     for (i = 1, j = r, top = N; i <= C; ++i) {
67         v = c[i];
68         while (j != fa[u] && (dis[v] - dis[j] <= l[v])) insert(j), j = fa[j];
69         if (top != N) {
70             int k = query(p[v]); 
71             gmin(dp[v], (dis[v] - dis[k]) * p[v] + q[v] + dp[k]);
72         }
73     }
74     for (i = 0; i < g[r].size(); ++i)
75         solve(g[r][i].v, sz[g[r][i].v]);
76 }
77 int main() {
78     read(n); read(nnn); mx[0] = 0x3f3f3f3f;
79     for (int i = 2; i <= n; ++i) {
80         ll w; read(fa[i]); read(w); ae(fa[i], i, w);
81         read(p[i]); read(q[i]); read(l[i]); dp[i] = 1ll << 60;
82         dis[i] = dis[fa[i]] + w;
83     } solve(1, n);
84     for (int i = 2; i <= n; ++i) printf("%lld\n", dp[i]);
85     return 0;    
86 }

 

posted @ 2018-01-09 16:43  p0ny  阅读(123)  评论(0编辑  收藏  举报