POJ - 3162 Walking Race 树形dp 单调队列
POJ - 3162Walking Race
题目大意:有n个训练点,第i天就选择第i个训练点为起点跑到最远距离的点,然后连续的几天里如果最远距离的最大值和最小值的差距不超过m就可以作为观测区间,问这样的区间最长的长度?
一开始楞是没看懂题意,最讨厌这种四级题,这是在刁难我英语小能手(能用翻译的就不自己动手)。而且这题感觉单调队列那里的处理更难一点,不过还是来说一说怎么树形dp取得最远距离,先画个简简单单丑丑的图

我们直接从1作为根节点开始dfs的话,可以处理1的最远距离,并且可以得出到其它节点在其子树中的最短距离,然后怎么得到其他节点的最远距离呢?我们还是从1开始,2的最短距离无非就是1和2连接这一条边再加上除这条外的最长分支也就是1和4这条边,而3的话1和3连接的这条边是在1和4这条路径上的,所以对3来说最远距离就是1的除1和4这条外其他最长分支加上1和3连接的这条边与3和4连接的这条边中的最大值,所以我们可以更新一个每个节点的最大距离以及第二远距离还有最远距离来自哪个子节点的方向。
这样的话先一遍dfs得出作为根节点的情况,还有其他节点到子树的情况,然后第二边dfs再由根节点去传入数据更新其他节点的最大值,也就判断子节点是否是最远距离方向的,是的话传入第二远距离,否则传入最远距离。
然后就是取区间那里了,首先尺取思想,但需要一个单调递减队列维护区间最大值(最大值在队列首部),然后还需要一个单调递增队列维护区间最小值(最小值在队列首部),然后区间往右的同时,更新左端,详情见代码。
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
const int N=;
struct Side{
int v,ne,len;
}S[*N];
int sn,n,m,head[N],dis1[N],dis2[N],path[N];
void add(int u,int v,int c)
{
S[sn].v=v;
S[sn].len=c;
S[sn].ne=head[u];
head[u]=sn++;
}
void updata(int u,int v,int dis)//更新距离
{
if(dis>dis1[u])//更新最大距离的来源点
path[u]=v;
dis2[u]=max(dis2[u],min(dis1[u],dis));
dis1[u]=max(dis1[u],dis);
}
void dfs1(int u,int f)
{
for(int i=head[u];i!=-;i=S[i].ne)
{
int v=S[i].v;
if(v!=f)
{
dfs1(v,u);//先搜索子节点
updata(u,v,dis1[v]+S[i].len);//更新
}
}
}
void dfs2(int u,int f,int len)
{
updata(u,f,len);//由父节点传入的距离更新距离
for(int i=head[u];i!=-;i=S[i].ne)
{
int v=S[i].v;
if(v!=f)
{
if(v==path[u])
dfs2(v,u,dis2[u]+S[i].len);
else
dfs2(v,u,dis1[u]+S[i].len);
}
}
}
int main()
{
int f,d;
while(~scanf("%d%d",&n,&m))
{
for(int i=;i<=n;i++)
{
head[i]=-;
dis1[i]=dis2[i]=;
}
sn=;
for(int i=;i<n;i++)
{
scanf("%d%d",&f,&d);
add(i+,f,d);
add(f,i+,d);
}
dfs1(,);
dfs2(,,);
deque<int> qx,qd;//qx单调递增队列,qd单调递减队列
int ans=; //注意是双向队列,单向没有back()
for(int i=,j=;i<=n;i++)//j是左端,i是右端
{
//维护单调性
while(qd.size()&&dis1[qd.back()]<dis1[i])
qd.pop_back();
while(qx.size()&&dis1[qx.back()]>dis1[i])
qx.pop_back();
qd.push_back(i);
qx.push_back(i);
while(qd.size()&&qx.size()&&dis1[qd.front()]-dis1[qx.front()]>m)
{
//当最大值减最小值大于m时这时左端的位置就需要调整了
//左端肯定是要调整到最大值和最小值中较近的位置的前面
if(qd.front()<qx.front())
{
j=qd.front();
qd.pop_front();
}
else
{
j=qx.front();
qx.pop_front();
}
//把区间外的数全部弹出
while(qd.size()&&qd.front()<=j)
qd.pop_front();
while(qx.size()&&qd.front()<=j)
qx.pop_front();
}
ans=max(ans,i-j);//更新区间长度
}
printf("%d\n",ans);
}
return ;
}
简简单单的低调
连做了几题树形dp,不怎么说得出,不过感觉还是有点心得的。核心的思想还是在于它的一棵数的结构,我们可以把某个节点假设为根节点再由它的情况去推导出整棵树的情况。而且精华部分也正如dp,搞清楚dp什么,然后是状态转移的过程。想练好它,无疑就两个方法,做题,思考。
POJ - 3162 Walking Race 树形dp 单调队列的更多相关文章
- POJ 3162.Walking Race 树形dp 树的直径
Walking Race Time Limit: 10000MS Memory Limit: 131072K Total Submissions: 4123 Accepted: 1029 Ca ...
- 【题解】poj 3162 Walking Race 树形dp
题目描述 Walking RaceTime Limit: 10000MS Memory Limit: 131072KTotal Submissions: 4941 Accepted: 1252Case ...
- 【POJ3162】Walking Race 树形dp+单调队列+双指针
题目大意:给定一棵 N 个节点的无根树,边有边权,现生成一个序列 d,d[i] 表示 i 号节点到树上其他节点距离的最大值.给定一个 m,求 d 序列中最大值和最小值之差不超过 m 的最长连续段的长度 ...
- POJ 3162 Walking Race 树形DP+线段树
给出一棵树,编号为1~n,给出数m 漂亮mm连续n天锻炼身体,每天会以节点i为起点,走到离i最远距离的节点 走了n天之后,mm想到知道自己这n天的锻炼效果 于是mm把这n天每一天走的距离记录在一起,成 ...
- POJ 3162 Walking Race 树形dp 优先队列
http://poj.org/problem?id=3162 题意 : 一棵n个节点的树.wc爱跑步,跑n天,第i天从第i个节点开始跑步,每次跑到距第i个节点最远的那个节点(产生了n个距离),现在要 ...
- HDU 4123 Bob’s Race 树形dp+单调队列
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4123 Time Limit: 5000/2000 MS (Java/Others) Memory L ...
- [POJ3162]Walking Race(DP + 单调队列)
传送门 题意:一棵n个节点的树.wc爱跑步,跑n天,第i天从第i个节点开始跑步,每次跑到距第i个节点最远的那个节点(产生了n个距离),现在要在这n个距离里取连续的若干天,使得这些天里最大距离和最小距离 ...
- (noip模拟二十一)【BZOJ2500】幸福的道路-树形DP+单调队列
Description 小T与小L终于决定走在一起,他们不想浪费在一起的每一分每一秒,所以他们决定每天早上一同晨练来享受在一起的时光. 他们画出了晨练路线的草图,眼尖的小T发现可以用树来描绘这个草图. ...
- POJ 3162 Walking Race(树形dp+单调队列 or 线段树)
http://poj.org/problem?id=3162 题意:一棵n个节点的树.有一个屌丝爱跑步,跑n天,第i天从第i个节点开始跑步,每次跑到距第i个节点最远的那个节点(产生了n个距离),现在要 ...
随机推荐
- python中while循环打印星星的四种形状
在控制台连续输出五行*,每一行星号数量一次递增 * ** *** **** ***** #1.定义一个行计数器 row = 1 while row <= 5: #定义一个列计数器 col = 1 ...
- 解决VS2005打开js,css,asp.php等文件,中文都是乱码的问题
用记事本打开可以正常观看但是用VS2005编辑器打开JS,中文确实乱码. 解决办法:在VS 2005 的设置里面选择自动检测Utf-8:“工具”->“选项”->“文本编辑器”->“自 ...
- python之输入一系列整数输出最大值
在python学习中,我们经常会遇到:编写一个程序,输入若干整数或者是在一串字符中,输出最大值(数)的问题.那么在这里,我给出了几种常见的,也是几种比较常用的方法,希望能给大家的学习带来一定的帮助. ...
- Java高并发程序设计学习笔记(十):并发调试和JDK8新特性
转自:https://blog.csdn.net/dataiyangu/article/details/87631574 多线程调试的方法使用Eclipse进行多线程调试线程dump及分析分析死锁案例 ...
- 入坑django2
数据模型 关于时间的字段设置 add_date = models.DateTimeField('保存日期',default = timezone.now) mod_date = models.Date ...
- 20、linux启动流程和救援模式
1.Linux启动流程 2.Linux运行级别 1.什么是运行级别,运行级别就是操作系统当前正在运行的功能级别 System V init运行级别 systemd目标名称 作用 0 runlevel0 ...
- 5、Sersync实时同步实战
1.实时同步概述 1.什么是实时同步, 只要当前目录发生变化则会触发一个事件,事件触发后将变化的目录同步至远程服务器. 2.为什么要实时同步, 保证数据的连续性, 减少人力维护成本, 解决nfs单点故 ...
- Linux awk命令 --三剑客老大
Linux awk命令 --三剑客老大 基本用法: awk [参数] ['找谁{干啥}'] 文件 参数: -F 分隔符 -v 创建或修改awk变量 OFS 输出分割符 awk显示每一列的时候分隔 ...
- Linux安装apidoc
一.安装apidoc所需环境(nodejs) 1. 查看系统是32位还是64位 uname -r 可以看出我这台linux的是64位的 2. 到node官网下载node的包并上传linux https ...
- Java语言开发的,直接解压即可使用软件
Tomcat ZooKeeper ActiveMQ Mycat