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 }