题目:https://www.luogu.org/problemnew/show/P1081

真是倍增好题!

预处理:f[i][j] 表示从 i 点开始走 2^j 次 AB (A,B各走一次)到达的点;

      sta[i][j] 表示从 i 点开始走 2^j 次 AB 后 A 走过的总路程;stb 为 B 的;

首先要找到 2^0 位置上的,也就是右边最近的和次近的点;

先把点按海拔排序,那么最近点和次近点一定在 i-2 , i-1 , i+1 , i+2 这四个位置;

又不能找到 i 之前的点,所以需要支持查询周边四个值并且可以删除的数据结构,可以用双向链表(用结构体存一个 l 和 r 即可);

然后倍增预处理出 f , sta , stb 数组,倍增查询即可;

倍增预处理时把 f 写成 sta,stb 改了好久囧...还是不能对应照抄上面一行啊...

还有一定注意预处理的倍增要外层 j 内层 i !

代码如下:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. using namespace std;
  6. typedef long long ll;
  7. int const maxn=1e5+,inf=1e9;
  8. int n,m,f[maxn][],h[maxn],p[maxn],na[maxn],nb[maxn];
  9. ll sta[maxn][],stb[maxn][];
  10. struct N{int id,h,l,r;}d[maxn];
  11. bool cmp(N x,N y){return (x.h==y.h)?x.id<y.id:x.h<y.h;}
  12. bool lf(int x,int l,int r)//是否选 l
  13. {
  14. if(!l)return ;
  15. if(!r)return ;
  16. return d[x].h-d[l].h<=d[r].h-d[x].h;//=
  17. }
  18. void init()
  19. {
  20. for(int i=;i<=n;i++)
  21. {
  22. f[i][]=nb[na[i]];
  23. sta[i][]=abs(h[i]-h[na[i]]);
  24. stb[i][]=abs(h[f[i][]]-h[na[i]]);
  25. }
  26. for(int j=;j<;j++)//外j内i
  27. for(int i=;i<=n;i++)
  28. {
  29. f[i][j]=f[f[i][j-]][j-];
  30. // sta[i][j]=sta[i][j-1]+sta[sta[i][j-1]][j-1];
  31. // stb[i][j]=stb[i][j-1]+stb[stb[i][j-1]][j-1];
  32. sta[i][j]=sta[i][j-]+sta[f[i][j-]][j-];//f!囧
  33. stb[i][j]=stb[i][j-]+stb[f[i][j-]][j-];
  34. }
  35. }
  36. void get(int p,ll x,ll &a,ll &b)//ll
  37. {
  38. a=; b=; ll d=;
  39. for(int i=;i>=;i--)
  40. if(f[p][i]&&d+sta[p][i]+stb[p][i]<=x)
  41. {
  42. a+=sta[p][i]; b+=stb[p][i];
  43. d+=sta[p][i]+stb[p][i]; p=f[p][i];
  44. }
  45. if(na[p]&&d+sta[p][]<=x)a+=sta[p][];//A再走一步
  46. }
  47. int main()
  48. {
  49. scanf("%d",&n);
  50. for(int i=;i<=n;i++)scanf("%d",&h[i]),d[i].h=h[i],d[i].id=i;
  51. sort(d+,d+n+,cmp);
  52. for(int i=;i<=n;i++)p[d[i].id]=i,d[i].l=i-,d[i].r=i+;
  53. d[].l=d[n].r=;
  54. for(int i=;i<=n;i++)
  55. {
  56. int j=p[i],l=d[j].l,r=d[j].r;
  57. if(lf(j,l,r))nb[i]=d[l].id,na[i]=(lf(j,d[l].l,r)?d[d[l].l].id:d[r].id);//id
  58. else nb[i]=d[r].id,na[i]=(lf(j,l,d[r].r)?d[l].id:d[d[r].r].id);
  59. if(l)d[l].r=r;
  60. if(r)d[r].l=l;//删除j
  61. }
  62. init();
  63. int ans; ll x; double mn=inf;
  64. scanf("%lld%d",&x,&m);
  65. ll a,b;
  66. for(int i=;i<=n;i++)
  67. {
  68. get(i,x,a,b);
  69. if(!b)continue;
  70. double k=1.0*a/b;
  71. if(mn>k)mn=k,ans=i;
  72. else if(mn==k&&h[ans]<h[i])ans=i;
  73. }
  74. printf("%d\n",ans);
  75. for(int i=,x,p;i<=m;i++)
  76. {
  77. scanf("%d%lld",&p,&x);
  78. get(p,x,a,b);
  79. printf("%lld %lld\n",a,b);
  80. }
  81. return ;
  82. }

洛谷 P1081 开车旅行 —— 倍增的更多相关文章

  1. 洛谷P1081 开车旅行(倍增)

    题意 题目链接 Sol 咕了一年的题解.. 并不算是很难,只是代码有点毒瘤 \(f[i][j]\)表示从\(i\)号节点出发走了\(2^j\)轮后总的距离 \(da[i][j]\)同理表示\(a\)的 ...

  2. 洛谷 P1081 开车旅行(70)

    P1081 开车旅行 题目描述 小AA 和小BB 决定利用假期外出旅行,他们将想去的城市从 11到 NN 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 ii的海 ...

  3. 2018.11.04 洛谷P1081 开车旅行(倍增)

    传送门 思路简单码量超凡? 感觉看完题大家应该都知道是倍增sbsbsb题了吧. 首先预处理出从每个点出发如果是AAA走到哪个点,如果是BBB走到哪个点. 然后利用刚刚预处理出的信息再预处理从每个点出发 ...

  4. 洛谷 P1081 开车旅行【双向链表+倍增】

    倍增数组的20和N写反了反复WAWAWA-- 注意到a和b在每个点上出发都会到一个指定的点,所以这样构成了两棵以n点为根的树 假设我们建出了这两棵树,对于第一问就可以枚举起点然后倍增的找出ab路径长度 ...

  5. [NOIP2012] 提高组 洛谷P1081 开车旅行

    题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 ...

  6. NOIP 2012 洛谷P1081 开车旅行

    Description: 就是两个人开车,只能向东开.向东有n个城市,城市之间的距离为他们的高度差.A,B轮流开车,A喜欢到次近的城市,B喜欢到最近的城市.如果车子开到底了或者车子开的路程已经超过了限 ...

  7. 洛谷P1081 开车旅行

    题目 双向链表+倍增+模拟. \(70pts\): 说白了此题的暴力就是细节较多的模拟题. 我们设离\(i\)城市最近的点的位置为\(B[i]\),第二近的位置为\(A[i]\).设\(A\)或\(B ...

  8. 洛谷P1081——开车旅行

    传送门:QAQQAQ 题意注意点: 1.是从前往后走,不能回头 2.小A小B轮流开,先小A开,而小A是到第二近的点(这点调试的时候查了好久) 3.若绝对值差相同海拔低的更近,而第一个询问若比值相同是海 ...

  9. 洛谷P1081 开车旅行70分

    https://www.luogu.org/problem/show?pid=1081 太遗憾了明明写出来了,却把最小值初始值弄小了,从第二个点开始就不可能对了.70分! #include<io ...

随机推荐

  1. JS高级——词法作用域

    作用域 1.js中没有块级作用域 2.如果有块级作用域,那么下面代码将会是undefined undefined <script> for (var i = 0; i < 10; i ...

  2. SQl基本操作——try catch

    begin try ... end try begin catch ... end catch

  3. RAID技术简单分析

    RAID技术解析 RAID:独立磁盘冗余阵列(Redundant Array of Independent Disks) RAID技术就是将许多块硬盘设备组合成一个容量更大.更安全的硬盘组,可以将数据 ...

  4. 实验2 C++数组与指针

    一.实验目的: 掌握一维数组和二维数组的定义.赋值和输入输出的方法. 掌握字符数组和字符串函数的使用. 通过实验进一步掌握指针的概念,会定义和使用指针变量. 能正确使用数组的指针和指向数组的指针变量. ...

  5. smtplib.SMTPDataError: (554, b'DT:SPM 126 smtp

    报错信息 smtplib.SMTPDataError: (554, b'DT:SPM 126 smtp7,DsmowAA3uguL7e1cyvkyFw--.22553S3 1559096715,ple ...

  6. 查询数据表行数 然后循环查找表 添加数据到ITEMS

    ;i<tbBiao.Rows.Count;i++) { string TableName = (tbBiao.Rows[i]["Table"]).ToString(); tb ...

  7. jquery from使用

    jquery form是一个基于jquery的表单异步提交的插件,通过它能快速简便的提交表单. html <div> <form id="ajaxForm" me ...

  8. xadmin站点管理类

    9. Xadmin xadmin是Django的第三方扩展,比使用Django的admin站点更强大也更方便. 文档:https://xadmin.readthedocs.io/en/latest/i ...

  9. Sending Secret Messages LightOJ - 1404

    Sending Secret Messages LightOJ - 1404 Alice wants to send Bob some confidential messages. But their ...

  10. chrome本地测试cookie时无效的原因

    https://blog.csdn.net/lyj787505955/article/details/38079079 应该是chrome的原因, 同一网页放在tomcat后,通过localhost方 ...