很综合的题目,出得非常好
第一个问题是求以树中的每个节点为起点所能走的最长路:
首先,求出各个点的最长路,次长路,以及最长路的后继节点,再据此得到答案
第二个问题,需要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; }