http://cogs.pro:8080/cogs/problem/problem.php?pid=vSXNiVegV
题意:给个树,第i个点有两个权值ai和bi,现在求一条长度为m的路径,使得Σai/Σbi最小。
思路:二分答案得p,把每个点权值变成ai-p*bi,看是否存在长为一条长为m的路使总和<=0。
tag数组表示从当前位置沿最长链走到底的值,dp数组初值表示从当前位置的重儿子走到底的值(加负号),用tag[...]+dp[..]维护从当前节点往下走若干步得到的最小值(只更新dp数组
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 # include <stdio.h> 2 # include <string.h> 3 # include <iostream> 4 # include <algorithm> 5 // # include <bits/stdc++.h> 6 7 using namespace std; 8 9 typedef long long ll; 10 typedef long double ld; 11 typedef unsigned long long ull; 12 const int N = 3e4 + 10, M = 6e4 + 10; 13 const int mod = 1e9+7; 14 15 int n, m, A[N * 7], B[N * 7], head[N], nxt[M], to[M], tot = 0; 16 inline void add(int u, int v) { 17 ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v; 18 } 19 inline void adde(int u, int v) { 20 add(u, v), add(v, u); 21 } 22 23 int dep[N], mxd[N], son[N], sz[N]; 24 inline void pre_dfs(int x, int fa = 0) { 25 dep[x] = dep[fa] + 1; 26 mxd[x] = dep[x]; son[x] = 0; 27 for (int i=head[x]; i; i=nxt[i]) { 28 if(to[i] == fa) continue; 29 pre_dfs(to[i], x); 30 if(mxd[to[i]] > mxd[x]) mxd[x] = mxd[to[i]], son[x] = to[i]; 31 } 32 sz[x] = mxd[x] - dep[x]; 33 } 34 35 int pos[N], idx; 36 inline void pre_pos(int x, int fa = 0) { 37 pos[x] = ++idx; 38 if(son[x]) pre_pos(son[x], x); 39 for (int i=head[x]; i; i=nxt[i]) 40 if(to[i] != fa && to[i] != son[x]) pre_pos(to[i], x); 41 } 42 43 double mid_check, ans; 44 double dp[N], tag[N]; 45 inline void solve(int x, int fa = 0) { 46 double *f = &dp[pos[x]], C = (double)A[x] - mid_check * B[x]; 47 if(son[x] == 0) { //leaf 48 f[0] = 0; tag[x] = C; 49 if(m == 0) ans = min(ans, tag[x]); 50 return ; 51 } 52 solve(son[x], x); f[0] = -tag[son[x]]; 53 tag[x] = tag[son[x]] + C; 54 for (int i=head[x], y; i; i=nxt[i]) { 55 if(to[i] == fa || to[i] == son[x]) continue; 56 solve(y = to[i], x); 57 double *g = &dp[pos[y]]; 58 for (int j=0; j<=sz[y] && j<m; ++j) 59 if(m-1-j <= sz[x]) ans = min(ans, f[m-1-j] + tag[x] + g[j] + tag[y]); 60 for (int j=0; j<=sz[y]; ++j) f[j+1] = min(f[j+1], g[j] + tag[y] + C - tag[x]); 61 } 62 if(m <= sz[x]) ans = min(ans, f[m] + tag[x]); 63 } 64 65 66 inline bool chk(double x) { 67 ans = 1e18; mid_check = x; 68 solve(1); 69 return ans <= 0; 70 } 71 72 int main() { 73 freopen("cdcq_b.in", "r", stdin); 74 freopen("cdcq_b.out", "w", stdout); 75 cin >> n >> m; 76 for (int i=1; i<=n; ++i) scanf("%d", A+i); 77 for (int i=1; i<=n; ++i) scanf("%d", B+i); 78 if(m == -1) { 79 double ans = 1e18; 80 for (int i=1; i<=n; ++i) ans = min(ans, (double)A[i]/B[i]); 81 printf("%.2lf\n", ans); 82 return 0; 83 } 84 for (int i=1, u, v; i<n; ++i) { 85 scanf("%d%d", &u, &v); 86 adde(u, v); 87 } 88 --m; 89 pre_dfs(1); 90 pre_pos(1); 91 double l = 0, r = 1e11, mid; 92 while(r-l > 1e-4) { 93 mid = (l+r)/2.0; 94 if(chk(mid)) r = mid; 95 else l = mid; 96 } 97 if(l > 5e10) puts("-1"); 98 else printf("%.2lf\n", l); 99 return 0; 100 }