[POJ3162]Walking Race(DP + 单调队列)
题意:一棵n个节点的树。wc爱跑步,跑n天,第i天从第i个节点开始跑步,每次跑到距第i个节点最远的那个节点(产生了n个距离),现在要在这n个距离里取连续的若干天,使得这些天里最大距离和最小距离的差小于M,问怎么取使得天数最多?
求每个点到最远距离的点的距离可以用 computer 的方法。
至于第二问,可以跑一遍2个单调队列。
具体是固定左端点,右端点向右平移到最远,直到不能平移,再左端点向右平移一位。在这中间维护单调队列和更新 ans 最大值。
具体细节看代码
——代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | #include <cstdio> #include <cstring> #include <iostream> #define N 1000001 #define max(x, y) ((x) > (y) ? (x) : (y)) int n, m, cnt, h1 = 1, t1, h2 = 1, t2, ans; int head[N], to[N << 1], val[N << 1], next[N << 1], f[N][3], a[N], q1[N], q2[N]; bool vis[N]; inline int read() { int x = 0, f = 1; char ch = getchar (); for (; ! isdigit (ch); ch = getchar ()) if (ch == '-' ) f = -1; for (; isdigit (ch); ch = getchar ()) x = (x << 1) + (x << 3) + ch - '0' ; return x * f; } inline void add( int x, int y, int z) { to[cnt] = y; val[cnt] = z; next[cnt] = head[x]; head[x] = cnt++; } inline void dfs1( int u) { int i, v, d1 = 0, d2 = 0; vis[u] = 1; for (i = head[u]; i ^ -1; i = next[i]) { v = to[i]; if (!vis[v]) { dfs1(v); if (f[v][0] + val[i] > d1) d2 = d1, d1 = f[v][0] + val[i]; else if (f[v][0] + val[i] > d2) d2 = f[v][0] + val[i]; } } f[u][0] = d1; f[u][1] = d2; } inline void dfs2( int u) { int i, v; vis[u] = 1; for (i = head[u]; i ^ -1; i = next[i]) { v = to[i]; if (!vis[v]) { if (f[v][0] + val[i] == f[u][0]) f[v][2] = f[u][1] + val[i]; else f[v][2] = f[u][0] + val[i]; f[v][2] = max(f[v][2], f[u][2] + val[i]); dfs2(v); } } } int main() { int i, x, y, z; while (~ scanf ( "%d %d" , &n, &m)) { ans = cnt = 0; memset (f, 0, sizeof (f)); memset (head, -1, sizeof (head)); for (i = 1; i < n; i++) { x = read(); y = read(); add(i + 1, x, y); add(x, i + 1, y); } memset (vis, 0, sizeof (vis)); dfs1(1); memset (vis, 0, sizeof (vis)); dfs2(1); for (i = 1; i <= n; i++) a[i] = max(f[i][0], f[i][2]); for (x = 1, y = 0; x <= n; x++) { while (q1[h1] < x && h1 <= t1) h1++; while (q2[h2] < x && h2 <= t2) h2++; while (a[q1[h1]] - a[q2[h2]] < m && y <= n) { y++; while (a[q1[t1]] < a[y] && h1 <= t1) t1--; q1[++t1] = y; while (a[q2[t2]] > a[y] && h2 <= t2) t2--; q2[++t2] = y; } ans = max(ans, y - x); } printf ( "%d\n" , ans); } return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步