很综合的题目,出得非常好
第一个问题是求以树中的每个节点为起点所能走的最长路:
首先,求出各个点的最长路,次长路,以及最长路的后继节点,再据此得到答案
第二个问题,需要rmq,并且维护一个队列,只要满足条件,队尾添加新元素,不然同时弹出队头
注意!dfs函数中tmp2为根走另一分支所得次长路,与最长路无公共路径!
#include <iostream>
using namespace std;
struct gtype {
int y,d,next;
}g[100010];
int first[50010],tot,x,y,d,s[50010],a[50010][4],n,m,q;
int MIN[50001][20],MAX[50001][20];
void add(int x,int y,int d) {
tot++;
g[tot].y = y;
g[tot].d = d;
g[tot].next = first[x];
first[x] = tot;
}
int dfs(int x,int fa) {
int tmp1 = 0, tmp2 = 0, vx = 0;
for (int t=first[x];t!=-1;t=g[t].next) {
int y = g[t].y;
if (y==fa) continue;
int tmp = g[t].d + dfs(y, x);
if (tmp > tmp1) {
tmp2 = tmp1;
tmp1 = tmp;
vx = y;
}
else if (tmp > tmp2) tmp2 = tmp;
}
a[x][0] = vx;
a[x][1] = tmp1;
a[x][2] = tmp2;
return tmp1;
}
void find(int x,int fa,int ans) {
int vx = a[x][0];
int tmp1 = a[x][1];
int tmp2 = a[x][2];
if (ans > tmp1) {
tmp2 = tmp1;
tmp1 = ans;
vx = 0;
}
else if (ans > tmp2) tmp2 = ans;
s[x-1] = tmp1;
for (int t=first[x];t!=-1;t=g[t].next) {
int y = g[t].y;
if (y==fa) continue;
if (y==vx) find(y,x,tmp2+g[t].d);
else find(y,x,tmp1+g[t].d);
}
}
int max(int x,int y) {
return s[x]>s[y]?x:y;
}
int min(int x,int y) {
return s[x]>s[y]?y:x;
}
void ST() {
int i,j;
for (i=0;i<=n;i++)
MIN[i][0]=MAX[i][0]=i;
for (j=1;1<<j<=n;j++)
for (i=0;i+(1<<j)-1<n;i++) {
MIN[i][j]=min(MIN[i][j-1],MIN[i+(1<<(j-1))][j-1]);
MAX[i][j]=max(MAX[i][j-1],MAX[i+(1<<(j-1))][j-1]);
}
}
int RMQ(int i,int j,int x) {//询问区间[i,j],x==1返回最大值下标,否则返回最小值下标
if (i>j) {
i^=j;j^=i;i^=j;
}
int k=0;
while (i+(1<<k)<j-(1<<k)+1) k++;
if(x==1)
return max(MAX[i][k],MAX[j-(1<<k)+1][k]);
return min(MIN[i][k],MIN[j-(1<<k)+1][k]);
}
int maxi(int a,int b) {
if (a>b) return a; else return b;
}
int main() {
while (scanf("%d%d",&n,&m)) {
if (n==0 && m==0) break;
tot = 0;
memset(g,0,sizeof(g));
memset(first,-1,sizeof(first));
for (int i=1;i<n;i++) {
scanf("%d%d%d",&x,&y,&d);
add(x,y,d);
add(y,x,d);
}
dfs(1,0);
find(1,0,0);
ST();
for (int i=1;i<=m;i++) {
scanf("%d",&q);
int head = 1, tail = 1, ans = 0;
while (tail <= n) {
int tmp1 = s[RMQ(head-1,tail-1,0)];
int tmp2 = s[RMQ(head-1,tail-1,1)];
if (tmp2-tmp1<=q) {
tail++;
ans = maxi(ans,tail-head);
}
else { head++;tail++; }
}
printf("%d\n",ans);
}
}
return 0;
}