倍增+双向链表——洛谷P1081 开车旅行
来源:互联网 发布:java开发面试题及答案 编辑:程序博客网 时间:2024/05/16 09:41
https://daniu.luogu.org/problem/show?pid=1081#sub
提高组的第三题;
哇;
首先题目很恶心;
然而发现也没什么歧义,也不难看懂;
70分的暴力做法;
n*n预处理出A[i],B[i]两个数组;
标表示在i点时小A和小B开车分别会走到哪里;
这个只要暴力高就好了;
指的一提的是负最大初始值1e9不够;
要3e9;
然后我们就可以发现也已搞一下优化;
我们把读入排序;
拍好后搞成一个双向链表;
然后按照点的先后顺序去枚举;
对于k点;
显然A[i],B[i];
出自双向链表的
k-1,k-2,k+1,k+2里面;
我们统计号好k之后直接把k删掉;
这样对于后面的k,链表里面的非k点的顺序一定比k后;
这样预处理时间就变成了nlogn;
然后我们把小A一天+小B一天合为一步;
用这个去搞倍增表;
然后直接像lca一样去倍增就好啦;
#include<iostream>#include<cstdio>#include<cstdlib>#include<algorithm>using namespace std;const int N=1e5+100;struct L2{ int v,l,r,num;//双向链表 }L[N];struct zz{//一个答案结构体 int a,b; zz(){a=b=0;}};int a[N],A[N],B[N],c[N];int f[N][20],AA[N][20],BB[N][20];//倍增表,AA BB是这段倍增区间A B的花费 int x,y,z,n,m;bool cmp(L2 a,L2 b){return a.v<b.v;}void make(int k){ int mst=3e9,med=3e9,aa=0,bb=0,v,m; m=L[k].l; if(m){ v=abs(L[k].v-L[m].v); if(v<mst||(v==mst&&L[k].v>L[m].v)){ med=mst; bb=aa; mst=v; aa=L[m].num; }else if(v<med||(v==med&&L[k].v>L[m].v)){ med=v; bb=L[m].num; } m=L[m].l; if(m){ v=abs(L[k].v-L[m].v); if(v<mst||(v==mst&&L[k].v>L[m].v)){ med=mst; bb=aa; mst=v; aa=L[m].num; }else if(v<med||(v==med&&L[k].v>L[m].v)){ med=v; bb=L[m].num; } } } m=L[k].r; if(m){ v=abs(L[k].v-L[m].v); if(v<mst||(v==mst&&L[k].v>L[m].v)){ med=mst; bb=aa; mst=v; aa=L[m].num; }else if(v<med||(v==med&&L[k].v>L[m].v)){ med=v; bb=L[m].num; } m=L[m].r; if(m){ v=abs(L[k].v-L[m].v); if(v<mst||(v==mst&&L[k].v>L[m].v)){ med=mst; bb=aa; mst=v; aa=L[m].num; }else if(v<med||(v==med&&L[k].v>L[m].v)){ med=v; bb=L[m].num; } } } A[L[k].num]=bb;//注意,我的写法比较怪异,A和aa翻一下的 B[L[k].num]=aa; L[L[k].r].l=L[k].l;//删除 L[L[k].l].r=L[k].r;}void makebz(){ for(int i=1;i<=n;i++){ f[i][0]=B[A[i]]; AA[i][0]=abs(a[i]-a[A[i]]); BB[i][0]=abs(a[A[i]]-a[B[A[i]]]); } for(int j=1;(1<<j)<=n;j++) for(int i=1;i<=n;i++) if(f[i][j-1]){ f[i][j]=f[f[i][j-1]][j-1]; AA[i][j]=AA[i][j-1]+AA[f[i][j-1]][j-1]; BB[i][j]=BB[i][j-1]+BB[f[i][j-1]][j-1]; }}zz work(int now,int x){ int aa=0,bb=0,j; while(1){ j=0; for(;f[now][j]&&(aa+AA[now][j]+bb+BB[now][j]<=x);j++); if(!j)break; j--; aa+=AA[now][j]; bb+=BB[now][j]; now=f[now][j]; } if(A[now]&&(aa+bb+abs(a[A[now]]-a[now])<=x))aa+=abs(a[A[now]]-a[now]); zz ans; //最后A可能还会走一下 ans.a=aa; ans.b=bb; return ans;}void outit1(){ int x,ans; double Ans=1e9+5,temp; zz c; scanf("%d",&x); for(int i=1;i<=n;i++){ c=work(i,x); if(!c.b)temp=1e9;else temp=(double)c.a/c.b; if(Ans>temp||(Ans==temp&&a[ans]<a[i]))Ans=temp,ans=i; } printf("%d\n",ans);}void outit2(){ int m,x,y; zz c; scanf("%d",&m); for(int i=1;i<=m;i++){ scanf("%d%d",&x,&y); c=work(x,y); printf("%d %d\n",c.a,c.b); }}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]),L[i].v=a[i],L[i].num=i; sort(L+1,L+n+1,cmp); for(int i=1;i<=n;i++){//创建一个链表 L[i].l=i-1; L[i].r=i+1; c[L[i].num]=i; } L[n].r=0; for(int i=1;i<=n;i++)make(c[i]);//按顺序来处理点 makebz();//做倍增表 outit1(); outit2();}
1 0
- 倍增+双向链表——洛谷P1081 开车旅行
- 洛谷P1081:开车旅行 (Treap+倍增)
- 洛谷 P1081 开车旅行
- 洛谷 P1081开车旅行
- 洛谷 P1081 [NOIP提高组 2012] 开车旅行(线段树+离散化+树上倍增)
- 洛谷 P1081 开车旅行(抄)
- Luogu P1081 [NOIp2012]开车旅行
- 【NOIP2012提高组D2T3】【洛谷P1081】开车旅行
- NOIP2012 开车旅行 (倍增)
- NOIP2012 开车旅行 【倍增】
- codevs1199开车旅行[倍增] 留坑
- noip2012 开车旅行 set+倍增
- NOIP2012 开车旅行:SET+倍增
- 【luogu1081】开车旅行(倍增)
- 【vijos1780】【NOIP2012】开车旅行 倍增
- NOIP2012 开车旅行 (倍增)
- 洛谷1081/codevs1199 开车旅行 链表,倍增,模拟
- noip2012 开车旅行 (倍增处理)
- 4-10
- jquery总结备忘
- windows 64位 创建MongoDB 服务
- LeetCode 376. Wiggle Subsequence 题解
- linux学习9练习题及答案
- 倍增+双向链表——洛谷P1081 开车旅行
- hough变换
- XML语法以及书写规范,Jaxp Dom解析XML
- 增强学习在无人驾驶中的应用
- [dsu on tree 主席树优化建图 最大流] BZOJ 3681 Arietta
- js动画效果之透明度变化
- printlimitmax
- POJ-2586-Y2K Accounting Bug [规律]
- 这位老哥拯救了我的平板!