hdu 4123 Bob’s Race

本文从WordPress迁移而来, 查看全部WordPress迁移文章

树dp

和poj 3162一样的题目,但是树的规模小一些,但是多个询问,解决方法是一模一样的。不过对于这题,找区间最小最大值要用RMQ也可以用(空间可以开得下)。

注意这题很神奇,RMQ会TLE,原因是使用log这个库函数,要用暴力的方法找出RMQ的那个k值,我是在程序一开始的时候先预处理出来,以后直接用。

想看具体分析的,搜索博客poj 3162即可

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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
#define N 50010
#define cl(xx,yy) memset((xx),(yy),sizeof((xx)))

int n,tot,head[N];
struct edge{
int v,w,next;
edge(){}
edge(int __v,int __w){
v = __v; w = __w;
}
}e[2*N];
int leaf[N][2];
int id[N][2];
int back[N],d[N];
int Pow[21],Log[N];
int dp1[N][21],dp2[N][21];

inline void add(int u ,int v,int w){
e[tot] = edge(v,w);
e[tot].next = head[u]; head[u] = tot++;
}

void dfs1(int u,int fa){
leaf[u][0] = leaf[u][1] = 0;
id[u][0] = id[u][1] = -1;
for(int k = head[u]; k != -1; k = e[k].next){
int v = e[k].v;
int w = e[k].w;
if(v == fa) continue;
dfs1(v,u);
if(leaf[v][0] + w > leaf[u][0]){
leaf[u][1] = leaf[u][0]; id[u][1] = id[u][0];
leaf[u][0] = leaf[v][0] + w; id[u][0] = v;
}
else if(leaf[v][0] + w > leaf[u][1]){
leaf[u][1] = leaf[v][0] + w; id[u][1] = v;
}
}
}

void dfs2(int len,int u,int fa){
if(fa != -1){
int res = 0;
res = max(res,len + back[fa]);
if(id[fa][0] != -1 && id[fa][0] != u){
res = max(res, len + leaf[fa][0]);
}
else if(id[fa][1] != -1 && id[fa][1] != u){
res = max(res , len + leaf[fa][1]);
}
back[u] = res;
d[u] = max(back[u],leaf[u][0]);
}
for(int k = head[u]; k != -1; k = e[k].next){
int v = e[k].v;
int w = e[k].w;
if(v == fa) continue;
dfs2(w , v , u);
}
}

inline void ST(int n){
int k = Log[n];
for(int i = 1; i <= n; i++)
dp1[i][0] = dp2[i][0] = d[i];
for(int j = 1; j <= k; j++)
for(int i = 1; i + Pow[j] - 1 <= n; i++){
dp1[i][j] = max(dp1[i][j-1] , dp1[i+Pow[j-1]][j-1]);
dp2[i][j] = min(dp2[i][j-1] , dp2[i+Pow[j-1]][j-1]);
}
}
inline int getmax(int a,int b){
int k = Log[b-a+1];
//int k = log(b-a+1.0) / log(2.0);
return max(dp1[a][k] , dp1[b-Pow[k]+1][k]);
}

inline int getmin(int a,int b){
int k = Log[b-a+1];
//int k = log(b-a+1.0) / log(2.0);
return min(dp2[a][k] , dp2[b-Pow[k]+1][k]);
}
int main(){
for(int i = 0; i <= 20; i++) Pow[i] = (1<<i);
for(int i = 1; i <= 50000; i++){
int k = 0;
while((1<<k) <= i) k++;
Log[i] = k-1;
}
int q;
while(scanf("%d%d",&n,&q)!=EOF){
if(!n && !q) break;
cl(head,-1); tot = 0;
for(int i = 1; i < n; i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w); add(v,u,w);
}
dfs1(1,-1);
back[1] = 0; d[1] = leaf[1][0];
dfs2(0,1,-1);
//for(int i = 1; i <= n; i++)
// printf("%d : %d %d %d %d\n",i,leaf[i][0],leaf[i][1],back[i],d[i]);
ST(n);

while(q--){
int m;
scanf("%d",&m);
int left = 1 , right = 1 , ans = 0;
while(right <= n){
int res1 = getmax(left,right);
int res2 = getmin(left,right);
if(res1 - res2 <= m){
ans = max(ans,right-left+1);
right++;
}
else left++;
if(n-left+1 <= ans) break;
}
printf("%d\n",ans);
}
}
return 0;
}