hdu4123-Bob’s Race(树形dp+rmq+尺取)
题意:Bob想要开一个运动会,有n个房子和n-1条路(一棵树),Bob希望每个人都从不同的房子开始跑,要求跑的尽可能远,而且每条路只能走最多一次。Bob希望所有人跑的距离的极差不大于q,如果起点的编号需要连续,那么最多多少个起点。
题解:首先求出每个点所能跑的最大距离(参考hdu2196),问题将转化成给n个数字,求差值不超过q的最大区间。m个询问,n个数,N<=50000 M<=500,所以对于每一次询问可以在O(n)的复杂度求解,st算法求区间最大最小值,尺取法求最大长度。
(去年做2196的时候做了两三天,这次一下就写出来了,而且没怎么调,1A,开心^_^
代码:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef long long ll; const int N = 50005; const int INF = 0x5f5f5f5f; struct Edge { int to, cost, next; } edge[N*2]; int head[N]; int cnt_edge; void add_edge(int u, int v, int c) { edge[cnt_edge].to = v; edge[cnt_edge].cost = c; edge[cnt_edge].next = head[u]; head[u] = cnt_edge++; } int d[N], mx[N], smx[N], mid[N], smid[N]; void dfs(int u, int fa) { smx[u] = mx[u] = 0; mid[u] = smid[u] = 0; for (int i = head[u]; ~i; i = edge[i].next) { int v = edge[i].to; int c = edge[i].cost; if (v == fa) continue; dfs(v, u); if (mx[v]+c > smx[u]) { smx[u] = mx[v]+c; smid[u] = v; } if (smx[u] > mx[u]) { swap(smx[u], mx[u]); swap(smid[u], mid[u]); } } } int ans[N]; void dfs(int u, int fa, int x) { if (fa == -1) { //没有父亲结点 向下的最大值就是最大值 d[u] = 0; } else if (mid[fa] == u) { d[u] = max(x+smx[fa], d[fa]+x); } else { d[u] = max(x+mx[fa], d[fa]+x); } ans[u] = max(d[u], mx[u]); for (int i = head[u]; ~i; i = edge[i].next) { int v = edge[i].to; int c = edge[i].cost; if (v == fa) continue; dfs(v, u, c); } } int f1[N][20], f2[N][20]; void init(int n) { // f[i,j]表示[i,i+2^j-1]区间最大值 // f[i,j]=max(d[i,j-1], d[i+2^(j-1),j-1]) for (int i = 1; i <= n; ++i) f2[i][0] = f1[i][0] = ans[i]; for (int j = 1; (1<<j) <= n; ++j) for (int i = 1; i+j-1 <= n; ++i) { f1[i][j] = max(f1[i][j-1], f1[i+(1<<j-1)][j-1]); f2[i][j] = min(f2[i][j-1], f2[i+(1<<j-1)][j-1]); } } int query(int l, int r) { int k = 0; while (1<<k+1 <= r-l+1) ++k; return max(f1[l][k], f1[r-(1<<k)+1][k]) - min(f2[l][k], f2[r-(1<<k)+1][k]); } int main() { int n, m; while (~scanf("%d%d", &n, &m) && n) { int u, v, c; memset(head, -1, sizeof head); cnt_edge = 0; for (int i = 1; i < n; ++i) { scanf("%d%d%d", &u, &v, &c); add_edge(u, v, c); add_edge(v, u, c); } //10000000 q dfs(1, -1); dfs(1, -1, 0); //for (int i = 1; i <= n; ++i) printf("d[%d]=%d\n", i, ans[i]); init(n); while (m--) { int q; scanf("%d", &q); int r = 1; int res = 0; for (int i = 1; i <= n; ++i) { while (r <= n && query(i, r) <= q) r++; res = max(res, r-i); } printf("%d\n", res); } } return 0; }