HDU 4123 Bob's Race:树的直径 + 单调队列 + st表

题目链接: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 }
原文地址:https://www.cnblogs.com/Leohh/p/8151330.html