题目大意:给定一棵树,每一个点都从当前位置走到距离最远的位置,1~n的连续区间中最大并且走的最远距离差值不超过Q的区间右多大。
思路:首先求出每个点能到达的最远距离,这一步有两种做法:
第一种做法是树形DP,两次dfs,第一次求出从每个节点不同儿子节点所能走到最远距离maxlen[0],次远距离maxlen[1],以及走到最远距离时经过的儿子节点maxid。第二次dfs,每个点u能到达的最远距离就是不在u子树上的结点和u之间的最远距离len 与 u到子孙节点的最远距离中的最大值,在dfs的过程中更新len ,这就要用到我们第一次求得的maxid,假如当前儿子是maxid,当前边权值是w,那么儿子的len就为len+w,否则len为max(len,maxlen[0])+w.这一种做法代码量较小,但思路相对复杂。
第二种做法,考虑树的直径,不难发现所有点能到达的最远点一定为直径的两个端点之一,那么我们先两次dfs求出直径再两次dfs计算出所有点能到达的最远距离。这种做法相对好想。
求出了所有点能到的最远距离后我们初始化rmq,然后用对于每个询问用尺取法O(n)扫一遍,具体就是用两个指针一个指向起点,一个指向终点,如果当前差值大于q那么头指针后移否则尾指针后移并更新答案。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 50500;
const int INF = 0x3f3f3f3f;
int n, m;
int maxlen[MAXN][2], maxid[MAXN], dist[MAXN];
struct Edge{
int to,next;
int w;
} edge[MAXN*2];
int head[MAXN],tot;
void init() {
tot = 0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w) {
edge[tot].to = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
void dfs1(int cur, int fa) {
maxlen[cur][0]=0, maxid[cur]=cur, maxlen[cur][1]=-1;
for(int i = head[cur]; i != -1; i = edge[i].next) {
int u = edge[i].to, w = edge[i].w;
if(u == fa) continue;
dfs1(u, cur);
if(maxlen[u][0]+w > maxlen[cur][0]) {
maxlen[cur][1] = maxlen[cur][0];
maxlen[cur][0] = maxlen[u][0] + w;
maxid[cur] = u;
}
else if(maxlen[u][0]+w > maxlen[cur][1]) maxlen[cur][1]=maxlen[u][0]+w;
}
}
void dfs2(int cur, int fa, int len) { //len为cur的非子树到cur的最远距离
dist[cur] = max(maxlen[cur][0], len);
for(int i = head[cur]; i != -1; i = edge[i].next) {
int u = edge[i].to, w = edge[i].w;
if(u == fa) continue;
if(u == maxid[cur]) dfs2(u, cur, max(maxlen[cur][1],len)+w);
else dfs2(u, cur, dist[cur]+w);
}
}
int dmin[MAXN][20], dmax[MAXN][20];
void RMQ_init() {
for(int i = 1; i <= n; i++) dmin[i][0] = dmax[i][0] = dist[i];
for(int j = 1; (1<<j) <= n; j++) {
for(int i = 1; i+(1<<j)-1 <= n; i++) {
dmin[i][j] = min(dmin[i][j-1], dmin[i+(1<<(j-1))][j-1]);
dmax[i][j] = max(dmax[i][j-1], dmax[i+(1<<(j-1))][j-1]);
}
}
}
int RMQ(int L, int R) {
int k = 0;
while((1<<(k+1)) <= R-L+1) k++;
return max(dmax[L][k], dmax[R-(1<<k)+1][k])-min(dmin[L][k], dmin[R-(1<<k)+1][k]);
}
int main() {
//freopen("input.txt", "r", stdin);
while(scanf("%d%d", &n, &m)==2 && n) {
init();
for(int i = 1; i < n; i++) {
int u, v, w; scanf("%d%d%d", &u, &v, &w);
addedge(u, v, w);
addedge(v, u, w);
}
dfs1(1, 0);
dfs2(1, 0, 0);
RMQ_init();
while(m--) {
int q; scanf("%d", &q);
int ed=0, ans=0;
for(int st = 1; st <= n; st++) {
if(ed == n) continue;
while(ed<n && RMQ(st, ed+1)<=q) ed++, ans=max(ans, ed-st+1);
}
printf("%d\n", ans);
}
}
return 0;
}