題目連結: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 }