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 }

HDU 4123 Bob's Race:单调队列 + st表

原文地址:https://www.cnblogs.com/Leohh/p/8151330.html

时间: 2024-10-12 22:51:10

HDU 4123 Bob's Race:单调队列 + st表的相关文章

hdu 4123 Bob’s Race (树的直径相关+rmq+单调队列思想)

Bob's Race Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2115    Accepted Submission(s): 658 Problem Description Bob wants to hold a race to encourage people to do sports. He has got trouble

hdu 4123 Bob’s Race(树形dp+RMQ)

题目链接:hdu 4123 Bob's Race 题目大意:一个城镇有N个住户,N-1条路连接两个住户,保证N个住户联通,M次询问,给定N条边的信息,包括连 接的住户序号以及路的长度.然后是M次询问,每次询问Q,要求找到最长的连续序号,使得Max(dis[i]) - Min(dis[i]) ≤ Q(l≤i≤r),输出最大的r-l+1.dis[i]为从第i个住户出发,不重复走过路能移动的最远距离. 解题思路:树形dp,通过两次dfs,第1次处理出每个节点中孩子节点移动的最长距离和第二长距离,第2次

HDU 4123 Bob’s Race 树的直径+单调队列

题意: 给定n个点的带边权树Q个询问. 下面n-1行给出树 下面Q行每行一个数字表示询问. 首先求出dp[N] :dp[i]表示i点距离树上最远点的距离 询问u, 表示求出 dp 数组中最长的连续序列使得序列中最大值-最小值 <= u,输出这个序列的长度. 思路: 求dp数组就是求个树的直径然后dfs一下. 对于每个询问,可以用一个单调队列维护一下.O(n)的回答. #include <cstdio> #include <cstring> #include <strin

HDU 4123 Bob’s Race

Bob’s Race Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4123 Description Bob wants to hold a race to encourage people to do sports. He has got trouble in choosing the route. There are N houses and N - 1 roads

hdu 4123 Bob’s Race 树的直径+rmq+尺取

Bob’s Race Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description Bob wants to hold a race to encourage people to do sports. He has got trouble in choosing the route. There are N houses and N - 1 roads

POJ1821 单调队列//ST表 优化dp

http://poj.org/problem?id=1821 当我们在考虑内层循环j以及决策k的时候,我们可以把外层变量i看作定值,以此来优化dp状态转移方程. 题意 有n个工人准备铺m个连续的墙,每个工人有他必须图的一面墙壁Si,最多连续铺Li,每铺一个就花费Ci的钱,问最多要多少钱: 朴素算法很好想,就dp[i][j]维护i工人到这j层墙壁的最大值,对于每个工人去枚举他涂墙壁的开头和结尾然后更新即可. 时间复杂度O(NMM) M的范围是16000,很显然会T,我们考虑状态转移方程. 对于每个

HDU 4123 Bob’s Race(RMQ)

题意是说给出一棵树,N(10^5)个顶点,以及每条边的权值,现在需要选择连续的K个点(顶点编号连续),可以被选出来的条件是: 若d[i]代表顶点i到树上其他点的距离的最大值,使得区间[a, b]的d值的最大差值不大于Q, 也就是max(d[a], d[a + 1], ..., d[b]) - max(d[a], d[a + 1], ..., d[b]) <= Q Q是给出的一个查询(共有m<=500个查询),求对应每一个查询的K的最大值 思路是首先预处理出每个点到其他点的最大距离, 这可以通过

HDOJ 题目4123 Bob’s Race(树的直径+RMQ优化)

Bob's Race Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2753    Accepted Submission(s): 888 Problem Description Bob wants to hold a race to encourage people to do sports. He has got trouble

HDU 6047 Maximum Sequence (贪心+单调队列)

题意:给定一个序列,让你构造出一个序列,满足条件,且最大.条件是 选取一个ai <= max{a[b[j], j]-j} 析:贪心,贪心策略就是先尽量产生大的,所以就是对于B序列尽量从头开始,由于数据比较大,采用桶排序,然后维护一个单调队列,使得最头上最大. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #i