hdu4123-Bob’s Race(树形dp+rmq+尺取)

时间:2022-08-06 07:29:11

题意: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 = ;
const int INF = 0x5f5f5f5f;
struct Edge {
int to, cost, next;
} edge[N*];
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] = ;
mid[u] = smid[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);
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 == -) { //没有父亲结点 向下的最大值就是最大值
d[u] = ;
} 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][], f2[N][];
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 = ; i <= n; ++i) f2[i][] = f1[i][] = ans[i];
for (int j = ; (<<j) <= n; ++j)
for (int i = ; i+j- <= n; ++i) {
f1[i][j] = max(f1[i][j-], f1[i+(<<j-)][j-]);
f2[i][j] = min(f2[i][j-], f2[i+(<<j-)][j-]);
}
} int query(int l, int r)
{
int k = ;
while (<<k+ <= r-l+) ++k;
return max(f1[l][k], f1[r-(<<k)+][k]) - min(f2[l][k], f2[r-(<<k)+][k]);
} int main() {
int n, m;
while (~scanf("%d%d", &n, &m) && n) {
int u, v, c;
memset(head, -, sizeof head);
cnt_edge = ;
for (int i = ; i < n; ++i) {
scanf("%d%d%d", &u, &v, &c);
add_edge(u, v, c);
add_edge(v, u, c);
}
//10000000 q
dfs(, -);
dfs(, -, );
//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 = ;
int res = ;
for (int i = ; i <= n; ++i) {
while (r <= n && query(i, r) <= q) r++;
res = max(res, r-i);
}
printf("%d\n", res);
}
}
return ;
}