博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
POJ - 3162 Walking Race 树形dp 单调队列
阅读量:4356 次
发布时间:2019-06-07

本文共 2621 字,大约阅读时间需要 8 分钟。

Walking 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再由根节点去传入数据更新其他节点的最大值,也就判断子节点是否是最远距离方向的,是的话传入第二远距离,否则传入最远距离。

  然后就是取区间那里了,首先尺取思想,但需要一个单调递减队列维护区间最大值(最大值在队列首部),然后还需要一个单调递增队列维护区间最小值(最小值在队列首部),然后区间往右的同时,更新左端,详情见代码。

1 #include
2 #include
3 #include
4 using namespace std; 5 const int N=1000118; 6 struct Side{ 7 int v,ne,len; 8 }S[2*N]; 9 int sn,n,m,head[N],dis1[N],dis2[N],path[N]; 10 void add(int u,int v,int c) 11 { 12 S[sn].v=v; 13 S[sn].len=c; 14 S[sn].ne=head[u]; 15 head[u]=sn++; 16 } 17 void updata(int u,int v,int dis)//更新距离 18 { 19 if(dis>dis1[u])//更新最大距离的来源点 20 path[u]=v; 21 dis2[u]=max(dis2[u],min(dis1[u],dis)); 22 dis1[u]=max(dis1[u],dis); 23 } 24 void dfs1(int u,int f) 25 { 26 for(int i=head[u];i!=-1;i=S[i].ne) 27 { 28 int v=S[i].v; 29 if(v!=f) 30 { 31 dfs1(v,u);//先搜索子节点 32 updata(u,v,dis1[v]+S[i].len);//更新 33 } 34 } 35 } 36 void dfs2(int u,int f,int len) 37 { 38 updata(u,f,len);//由父节点传入的距离更新距离 39 for(int i=head[u];i!=-1;i=S[i].ne) 40 { 41 int v=S[i].v; 42 if(v!=f) 43 { 44 if(v==path[u]) 45 dfs2(v,u,dis2[u]+S[i].len); 46 else 47 dfs2(v,u,dis1[u]+S[i].len); 48 } 49 } 50 } 51 int main() 52 { 53 int f,d; 54 while(~scanf("%d%d",&n,&m)) 55 { 56 for(int i=0;i<=n;i++) 57 { 58 head[i]=-1; 59 dis1[i]=dis2[i]=0; 60 } 61 sn=0; 62 for(int i=1;i
qx,qd;//qx单调递增队列,qd单调递减队列 71 int ans=0; //注意是双向队列,单向没有back() 72 for(int i=1,j=0;i<=n;i++)//j是左端,i是右端 73 { 74 //维护单调性 75 while(qd.size()&&dis1[qd.back()]
dis1[i]) 78 qx.pop_back(); 79 qd.push_back(i); 80 qx.push_back(i); 81 while(qd.size()&&qx.size()&&dis1[qd.front()]-dis1[qx.front()]>m) 82 { 83 //当最大值减最小值大于m时这时左端的位置就需要调整了 84 //左端肯定是要调整到最大值和最小值中较近的位置的前面 85 if(qd.front()
简简单单的低调

  连做了几题树形dp,不怎么说得出,不过感觉还是有点心得的。核心的思想还是在于它的一棵数的结构,我们可以把某个节点假设为根节点再由它的情况去推导出整棵树的情况。而且精华部分也正如dp,搞清楚dp什么,然后是状态转移的过程。想练好它,无疑就两个方法,做题,思考。

转载于:https://www.cnblogs.com/LMCC1108/p/10534663.html

你可能感兴趣的文章
webpack构建react应用三:使用webpack Loaders 模块加载器(一)
查看>>
Java JDBC
查看>>
走势终完美 --执子之手
查看>>
补全左括号
查看>>
javascript中关于坐标 大小 的描述
查看>>
8086CPU各寄存器的用途
查看>>
AngularJs中,如何在render完成之后,执行Js脚本
查看>>
Nginx 防盗链
查看>>
如何讓Android系統顯示CJK擴展區漢字
查看>>
Android 下拉选择绑定Value和Text值
查看>>
HTML+CSS小结
查看>>
Android防止按钮连续点击
查看>>
ElasticSearch Mapping中的字段类型
查看>>
数据库中主键和外键的设计原则
查看>>
怎样理解阻塞非阻塞与同步异步的区别?
查看>>
Xcode 警告信息处理:Format string is not a string literal (potentially insecure)
查看>>
关于jQuery表单校验的应用
查看>>
matplotlib----初探------5直方图
查看>>
jquery之ajax
查看>>
Pro Git(中文版)
查看>>