题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4123
题意:
给你一棵树,n个节点,每条边有长度。
然后有m个询问,每个询问给定一个q值。
设dis[i]为:从节点i出发,不重复经过节点,所能够走的最远距离。
每次询问问你:区间[l,r]最长能有多长,同时保证 max{dis[i]} - min{dis[i]} <= q (i∈[l,r])
题解:
首先有一个结论:
从树上的任意一个节点出发,尽可能往远走,最终一定会到达树的直径的两个端点之一。
所以先两遍dfs1,找出直径的两个端点。
然后分别从两个端点dfs2,求出所有节点的dis[i]。
因为节点必须选编号连续的一段区间,所以可以用到单调队列。
枚举每个节点i加入队首。
然后对于每个i,不断地丢掉队尾pos++,直到当前的区间[pos,i]符合条件。
那么每次都需要判断是否有 max{dis[i]} - min{dis[i]} <= q (i∈[pos,i])
这就要用到st表了,然后O(1)判断就好。
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <vector> 5 #define MAX_N 50005 6 #define MAX_K 20 7 8 using namespace std; 9 10 struct Edge 11 { 12 int dest; 13 int len; 14 Edge(int _dest,int _len) 15 { 16 dest=_dest; 17 len=_len; 18 } 19 Edge(){} 20 }; 21 22 int n,m; 23 int maxd; 24 int st,ed; 25 int dis[MAX_N]; 26 int lg[MAX_N]; 27 int maxt[MAX_N][MAX_K]; 28 int mint[MAX_N][MAX_K]; 29 vector<Edge> edge[MAX_N]; 30 31 void read() 32 { 33 for(int i=1;i<=n;i++) edge[i].clear(); 34 int x,y,z; 35 for(int i=1;i<n;i++) 36 { 37 cin>>x>>y>>z; 38 edge[x].push_back(Edge(y,z)); 39 edge[y].push_back(Edge(x,z)); 40 } 41 } 42 43 void dfs1(int now,int p,int d,int &v) 44 { 45 if(d>maxd) 46 { 47 maxd=d; 48 v=now; 49 } 50 for(int i=0;i<edge[now].size();i++) 51 { 52 Edge temp=edge[now][i]; 53 if(temp.dest!=p) dfs1(temp.dest,now,d+temp.len,v); 54 } 55 } 56 57 void dfs2(int now,int p,int d) 58 { 59 dis[now]=max(dis[now],d); 60 for(int i=0;i<edge[now].size();i++) 61 { 62 Edge temp=edge[now][i]; 63 if(temp.dest!=p) dfs2(temp.dest,now,d+temp.len); 64 } 65 } 66 67 void init_st() 68 { 69 lg[0]=-1; 70 for(int i=1;i<=n;i++) 71 { 72 lg[i]=lg[i>>1]+1; 73 maxt[i][0]=mint[i][0]=dis[i]; 74 } 75 for(int k=1;(1<<k)<=n;k++) 76 { 77 for(int i=1;i+(1<<k)-1<=n;i++) 78 { 79 maxt[i][k]=max(maxt[i][k-1],maxt[i+(1<<(k-1))][k-1]); 80 mint[i][k]=min(mint[i][k-1],mint[i+(1<<(k-1))][k-1]); 81 } 82 } 83 } 84 85 int query_max(int l,int r) 86 { 87 int k=lg[r-l+1]; 88 return max(maxt[l][k],maxt[r-(1<<k)+1][k]); 89 } 90 91 int query_min(int l,int r) 92 { 93 int k=lg[r-l+1]; 94 return min(mint[l][k],mint[r-(1<<k)+1][k]); 95 } 96 97 void work() 98 { 99 maxd=-1; 100 dfs1(1,-1,0,st); 101 maxd=-1; 102 dfs1(st,-1,0,ed); 103 memset(dis,-1,sizeof(dis)); 104 dfs2(st,-1,0); 105 dfs2(ed,-1,0); 106 init_st(); 107 while(m--) 108 { 109 int q; 110 cin>>q; 111 int ans=1; 112 int pos=1; 113 for(int i=1;i<=n;i++) 114 { 115 while(query_max(pos,i)-query_min(pos,i)>q) pos++; 116 ans=max(ans,i-pos+1); 117 } 118 cout<<ans<<endl; 119 } 120 } 121 122 int main() 123 { 124 while(cin>>n>>m) 125 { 126 if(n==0 && m==0) break; 127 read(); 128 work(); 129 } 130 }