HDU 4123 Bob's Race:樹的直徑 + 單調佇列 + st表

Leohh發表於2017-12-30

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

 

相關文章