洛谷 P1081 开车旅行【双向链表+倍增】
倍增数组的20和N写反了反复WAWAWA……
注意到a和b在每个点上出发都会到一个指定的点,所以这样构成了两棵以n点为根的树
假设我们建出了这两棵树,对于第一问就可以枚举起点然后倍增的找出ab路径长度的比值,第二问同理,这里倍增的时候注意是先跳a再跳b,所以同一个点b的倍增数组要从a在这个点的的父亲开始,然后位置倍增数组也是这样,这样位置倍增相当于跳完a再跳b
然后这个树怎么建呢,开一个双向链表,表内按h排升序,因为一个点的最大次大值一定在比它小的值中最大的两个和比它大的值中最小的两个之中,所以直接用链表查即可,然后查完一个点就把它删掉,因为这个点不能用来更新id比他大的点
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=100005;
int n,m,rl[N],ff[N],gg[N];
long long h[N],f[20][N],g[20][N],fa[20][N],da,db;
struct qwe
{
int id,l,r;
long long h;
}a[N];
bool cmp(const qwe &a,const qwe &b)
{
return a.h<b.h;
}
int read()
{
int r=0,f=1;
char p=getchar();
while(p>'9'||p<'0')
{
if(p=='-')
f=-1;
p=getchar();
}
while(p>='0'&&p<='9')
{
r=r*10+p-48;
p=getchar();
}
return r*f;
}
void wk(int w,long long x)
{
da=0,db=0;
for(int i=17;i>=0;i--)
if(fa[i][w]!=0&&da+db+f[i][w]+g[i][w]<=x)
da+=f[i][w],db+=g[i][w],w=fa[i][w];
if(ff[w]!=0&&da+db+f[0][w]<=x)
da+=f[0][w];
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
h[i]=a[i].h=read(),a[i].id=i;
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)
rl[a[i].id]=i,a[i].l=i-1,a[i].r=i+1;
a[0].h=1e10,a[n+1].h=1e10;
for(int i=1;i<=n;i++)
{
int ll=a[a[rl[i]].l].l,l=a[rl[i]].l,r=a[rl[i]].r,rr=a[a[rl[i]].r].r;
if(!l)
gg[i]=a[r].id,ff[i]=a[rr].id;
else if(r==n+1)
gg[i]=a[l].id,ff[i]=a[ll].id;
else if(abs(h[i]-a[l].h)<=abs(h[i]-a[r].h))
gg[i]=a[l].id,ff[i]=(abs(h[i]-a[ll].h)<=abs(h[i]-a[r].h))?a[ll].id:a[r].id;
else
gg[i]=a[r].id,ff[i]=(abs(h[i]-a[l].h)<=abs(h[i]-a[rr].h))?a[l].id:a[rr].id;
a[a[rl[i]].l].r=a[rl[i]].r,a[a[rl[i]].r].l=a[rl[i]].l;
// cerr<<" "<<ff[i]<<" "<<gg[i]<<endl;
}
for(int i=1;i<=n;i++)
{
fa[0][i]=gg[ff[i]];
f[0][i]=abs(h[ff[i]]-h[i]);
g[0][i]=abs(h[fa[0][i]]-h[ff[i]]);
}
for(int i=1;i<=17;i++)
for(int j=1;j<=n;j++)
fa[i][j]=fa[i-1][fa[i-1][j]],f[i][j]=f[i-1][j]+f[i-1][fa[i-1][j]],g[i][j]=g[i-1][j]+g[i-1][fa[i-1][j]];
long long x0=read(),w=0;
double ans=1e18;
for(int c=1;c<=n;c++)
{
wk(c,x0);
if(db!=0&&1.0*da/db<ans)
{
ans=1.0*da/db;
w=c;
}
}
printf("%d\n",w);
m=read();
while(m--)
{
long long s=read(),x=read();
wk(s,x);
printf("%lld %lld\n",da,db);
}
return 0;
}
洛谷 P1081 开车旅行【双向链表+倍增】的更多相关文章
- 2018.11.04 洛谷P1081 开车旅行(倍增)
传送门 思路简单码量超凡? 感觉看完题大家应该都知道是倍增sbsbsb题了吧. 首先预处理出从每个点出发如果是AAA走到哪个点,如果是BBB走到哪个点. 然后利用刚刚预处理出的信息再预处理从每个点出发 ...
- 洛谷 P1081 开车旅行(70)
P1081 开车旅行 题目描述 小AA 和小BB 决定利用假期外出旅行,他们将想去的城市从 11到 NN 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 ii的海 ...
- 洛谷P1081 开车旅行
题目 双向链表+倍增+模拟. \(70pts\): 说白了此题的暴力就是细节较多的模拟题. 我们设离\(i\)城市最近的点的位置为\(B[i]\),第二近的位置为\(A[i]\).设\(A\)或\(B ...
- 洛谷 P1081 开车旅行 —— 倍增
题目:https://www.luogu.org/problemnew/show/P1081 真是倍增好题! 预处理:f[i][j] 表示从 i 点开始走 2^j 次 AB (A,B各走一次)到达的点 ...
- 洛谷P1081 开车旅行(倍增)
题意 题目链接 Sol 咕了一年的题解.. 并不算是很难,只是代码有点毒瘤 \(f[i][j]\)表示从\(i\)号节点出发走了\(2^j\)轮后总的距离 \(da[i][j]\)同理表示\(a\)的 ...
- [NOIP2012] 提高组 洛谷P1081 开车旅行
题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 ...
- NOIP 2012 洛谷P1081 开车旅行
Description: 就是两个人开车,只能向东开.向东有n个城市,城市之间的距离为他们的高度差.A,B轮流开车,A喜欢到次近的城市,B喜欢到最近的城市.如果车子开到底了或者车子开的路程已经超过了限 ...
- 洛谷P1081——开车旅行
传送门:QAQQAQ 题意注意点: 1.是从前往后走,不能回头 2.小A小B轮流开,先小A开,而小A是到第二近的点(这点调试的时候查了好久) 3.若绝对值差相同海拔低的更近,而第一个询问若比值相同是海 ...
- 洛谷P1081 开车旅行70分
https://www.luogu.org/problem/show?pid=1081 太遗憾了明明写出来了,却把最小值初始值弄小了,从第二个点开始就不可能对了.70分! #include<io ...
随机推荐
- php装饰者模式
php装饰者模式 装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象. 示例: A.B.C编辑同一篇文章. class ...
- 【小记事】解除端口占用(Windows)
开发中有时会因为端口占用而导致起项目时报错(如下图),这时候只要解除端口占用即可. 解除端口占用: 1.打开cmd(win+r),查看端口占用情况 netstat -ano | findstr 端口号 ...
- 2017多校Round7(hdu6120~hdu6132)
补题进度:9/13 1001 待填坑 1002(数学推导) 题意 有一个按顺序的n个点的k叉树,问每个点子树个数的异或和是多少(n,k<=1e18) 分析 可以先求出最大的d,满足d以上都是满K ...
- ZXing 二维码解析生成工具类
原文:http://www.open-open.com/code/view/1455848023292 import com.google.zxing.*; import com.google.zxi ...
- IPTABLES基本例子
iptables –F #删除已经存在的规则 iptables -P INPUT DROP #配置默认的拒绝规则.基本规则是:先拒绝所有的服务,然后根据需要再添加新的规则. iptables -A I ...
- 【深入探索c++对象模型】data语义学二
单一继承中,base class 和derived class的对象都是从相同的地址开始,其间差异只在于derived class比较大,用以容纳自己的nonstatic members. 若vptr ...
- 【APUE】进程间通信之共享存储(mmap函数)
共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式,因为进程可以直接读写内存,而不需要任何数据的拷贝.对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只 ...
- MySQL学习系列之触发器
触发器简介 触发器作用: 监控某种事件并触发某种动作 触发语法: CREATE TRIGGER trigger_name trigger_event ON tbl_name FOR EACH ROW ...
- Java中正则Matcher类的matches()、lookAt()和find()的差别
參考博文地址:http://www.oseye.net/user/kevin/blog/170 1.matcher():仅仅有在整个字符串全然匹配才返回true,否则返回false. 可是假设部分匹配 ...
- 微信小程序 常见问题 小结
1.微信小程序 尺寸单位 rpx单位是微信小程序中css的尺寸单位,rpx可以根据屏幕宽度进行自适应.规定屏幕宽为750rpx.如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则 ...