记得去年每场亚洲赛都以惨败告终,今年是自己最后一次参加ACM了。
其实自己挺喜欢ACM这个比赛的,只是自己没能达到大牛级别,根本不能靠ACM的成绩找工作,所以,只能早早放弃ACM,但其实感觉挺对不起韩boss的,所以,我试着想将cl123的实力提上去,这样,以后走的也安心点。
最后一个暑假了,要好好加油,争取明年亚洲赛拿个铜吧,银什么的也不期望,个人认为自己实力还达不到拿银的程度,如果真让自己拿了,含金量肯定不高。。。
现在已经被hdu的人虐爆了,估计想超上他们概率已经很低了,除非队友大爆发(主要是肯下功夫练就行),实力瞬间提高(虽然两个人智商都比我高,但是瞬间是不可能的- -||),不过这个除非没可能,一个无心ACM,一个天天dota,最后一次ACM区域赛也就没什么好奢望的了。。。。
此题是树状DP+RMQ,话说,我怎么觉得去年那场福州赛RMQ有用到好多,其实B题应该也是能用RMQ去AC的,可能用单调队列比较方便,RMQ有点小题大做了,但是RMQ真能AC啊啊啊啊!!!为什么没有解题报告有RMQ 来AC的呢!!!只有discuss中看到有一个人跟我的想法一样。。。。无奈~
网上好多解题报告说这是树状DP,其实也就是两次dfs,看不出来有DP的部分。
步骤如下:
1》先dfs求出每个节点的到其子节点的距离的最大值和次最大值,即记录以该节点X为根节点的子树,X到其子节点最远距离的值和次最远距离的值;
2》第二次dfs,求出该节点X经过父节点所能到达的最远距离为:
1)如果X到其父节点的距离加上X到其子节点的最远距离的和等于父节点的最远距离,那么就使用父节点的次最远距离作为最远距离(至于为什么这样?可以假定如果其父节点的最远距离就是由X节点的最远距离+X节点到父节点距离的和,那么只能使用其次最远距离,如果不是,那么其次最远距离肯定等于最远距离)
2)如果X到其父节点的距离+X到其子节点的最远距离不等于父节点的最远距离,那么就使用父节点的最远距离作为最远距离;
3》取该节点X经过父节点所能到达的最远距离和X节点到子节点最远距离中的最大值作为X所能到达的最远距离。
4》利用RMQ求区间的最值,这里要注意RMQ必须使用for循环的,而不要使用log的,否则会TLE,我第一次提交TLE就是因为用了log的RMQ,当时以为自己想法错了,但无论怎么计算复杂度都没有能超时的地方,后来有看他们说必须使用for循环的RMQ。
5》在枚举区间的时候可以用点小贪心。
#include<stdio.h>
#include<string>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<iostream>
using namespace std;
#define maxs( a , b ) a>b?a:b
#define mins( a , b ) a>b?b:a
#define M 50500
struct Point {
int maxn, minn;
} pnt[M];
struct node {
int u, v, next, c;
int flag;
} edge[M * 2];
int head[M], tot;
bool mark[M];
int l[M];
void Swap(int &x, int &y) {
int t = x;
x = y;
y = t;
}
void _add(int u, int v, int c) {
edge[tot].u = u;
edge[tot].v = v;
edge[tot].c = c;
edge[tot].flag = false;
edge[tot].next = head[u];
head[u] = tot++;
}
void add(int u, int v, int c) {
_add(u, v, c);
_add(v, u, c);
}
void dfs(int x) {
mark[x] = true;
pnt[x].maxn = pnt[x].minn = 0;
for (int i = head[x]; i != -1; i = edge[i].next) {
if (mark[edge[i].v] == false) {
edge[i].flag = true;
dfs(edge[i].v);
int t = pnt[edge[i].v].maxn + edge[i].c;
if (t > pnt[x].minn && t <= pnt[x].maxn) {
pnt[x].minn = t;
} else if (t > pnt[x].minn && t > pnt[x].maxn) {
Swap(pnt[x].maxn, pnt[x].minn);
pnt[x].maxn = t;
}
}
}
}
void dfs1(int x) {
for (int i = head[x]; i != -1; i = edge[i].next) {
if (edge[i].flag) {
int t;
if (pnt[x].maxn == pnt[edge[i].v].maxn + edge[i].c) {
t = pnt[x].minn + edge[i].c;
} else {
t = pnt[x].maxn + edge[i].c;
}
if (t > pnt[edge[i].v].minn && t <= pnt[edge[i].v].maxn) {
pnt[edge[i].v].minn = t;
} else if (t > pnt[edge[i].v].minn && t > pnt[edge[i].v].maxn) {
Swap(pnt[edge[i].v].maxn, pnt[edge[i].v].minn);
pnt[edge[i].v].maxn = t;
}
l[edge[i].v] = pnt[edge[i].v].maxn;
dfs1(edge[i].v);
}
}
}
int st1[20][M], st2[20][M];
int n;
void create_Dpmax() {
for (int j = 0; j < n; ++j)
st1[0][j] = l[j];
for (int i = 0; i + 1 < 20; ++i)
for (int j = 0; j + (1 << i) < n; ++j)
st1[i + 1][j] = max(st1[i][j], st1[i][j + (1 << i)]);
}
// [begin, end)
int getmax(int begin, int end) {//max{val[begin],val[begin + 1]......val[end - 1]}
int k = 0;
while ((1 << (k + 1)) < end - begin)
++k;
return max(st1[k][begin], st1[k][end - (1 << k)]);
}
void create_Dpmin() {
for (int j = 0; j < n; ++j)
st2[0][j] = l[j];
for (int i = 0; i + 1 < 20; ++i)
for (int j = 0; j + (1 << i) < n; ++j)
st2[i + 1][j] = min(st2[i][j], st2[i][j + (1 << i)]);
}
// [begin, end)
int getmin(int begin, int end) {//min{val[begin],val[begin + 1]......val[end - 1]}
int k = 0;
while ((1 << (k + 1)) < end - begin)
++k;
return min(st2[k][begin], st2[k][end - (1 << k)]);
}
int Dist(int x, int y) {
return getmax(x - 1, y) - getmin(x - 1, y);
}
int main() {
int m, i, j;
while (scanf("%d%d", &n, &m) != EOF) {
if (n == 0 && m == 0) {
break;
}
memset(head, -1, sizeof (head));
tot = 0;
for (i = 1; i < n; i++) {
int u, v, c;
scanf("%d%d%d", &u, &v, &c);
add(u, v, c);
}
memset(mark, false, sizeof (mark));
dfs(1);
l[1] = pnt[1].maxn;
dfs1(1);
for (i = 0; i < n; i++) {
l[i] = l[i + 1];
}
create_Dpmin();
create_Dpmax();
while (m--) {
int q;
scanf("%d", &q);
int ans = 1;
for (i = 1; i <= n - ans; i++) {
for (j = i + ans; j <= n;) {
if (Dist(i, j) <= q) {
j++;
if (j - i > ans) {
ans = j - i;
}
} else {
break;
}
}
}
printf("%d\n", ans);
}
}
return 0;
}