P1081 开车旅行    题面较为啰嗦。大概概括:一个数列,只能从一个点向后走,两种方案:A.走到和自己差的绝对值次小的点B.走到和自己差的绝对值最小点;花费为此差绝对值;若干询问从规定点向后最多花费$X$,且以移动方式A开始每走一次切换一次方式。求以A、B方式各花费多少。


不看题解切紫题一遍过了,兴奋~然而连想带写花了四小时左右,真要在noip考场上怕不是要凉。。。我太菜了QwQ

先看第一问,找比值最小点,实际上就是拆成$N$个询问,扔到第二问的询问里面做掉的说。所以主要看对于询问点怎么向后找终止点。可以猜出应该是$O(\log N)$一次询问,所以就要求高效的跳法。

考虑A若干次之后走到后面一个点,从这个点继续走,这样一个状态,很多询问都可能经历。所以对于一个点,希望预处理出以他为起点有关的信息。

维护从他开始的终点?显然不行。

若最远点$T_0$,可能当下到这起点已花了一些代价,由于代价制限导致走不到最远,大概能走到$T_1 < T_0$。也就是说,$S\sim T_1$这一段是我可以走过的,$T_1$之后都到不了。

所以可以根据实际情况二分查找最远点。实现起来,就是个倍增,到目标点要走$k$次,总是可以拆成走二的指数幂次叠加,枚举当前走的$2^i$次,可行就跳,不可行就呆原地。

这个是处理询问的方法。所以瓶颈就在于如何预处理倍增数组。坑死我了。

设计状态$fa[i][j],fb[i][j],to[i][j]$表示从$i$点出发,走$2^j$次,A、B各自花费,以及讫点。

对于底层$to[i][0]$,只采用A方式移动,找出后面次小代价即可。单独处理。

对于次底层$f[i][1]$,开始用AB轮流交替方式移动,所以在底层要顺便处理以B方式移动一次的相关信息,在这一层与A合并。

之后,由于每个状态都是走偶数次的,涉及转移状态都是以A开始的,比如我移动4次,由前2次和后2次拼接,这两段都是以A开始的。所以直接合并即可。

提一下最底层找相邻点的几种方法:

  • 每个点后面离他最近的。。前驱后继?平衡树?考虑用set来替代。找出大于他的两个,小于他的两个(没有则设为0),排一下序处理出来
  • set找4个点同上,然后。。分类讨论。。我的弱智方法。。。。qwq
  • 双向链表。可以将数组排序,将其用数组模拟成链表,之后,和每个点相邻的,虽然不一定是原来数组中他后面的元素,但是对于原数组1号,他在排序数组中相邻的肯定是前驱后继。找出之后将之从链表中删除,再考虑原数组的2号点,这时就不存在1号点的干扰了,后面同理。

常数稍大,但不影响能过,反正都是$O((N+M)\log N)$的。相关细节注意一下即可,如超出1e9提前特判掉等等。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#define dis first
#define pos second
#define dbg(x) cerr<<#x<<" = "<<x<<endl
#define _dbg(x,y) cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
template<typename T>inline char MIN(T&A,T B){return A>B?A=B,:;}
template<typename T>inline char MAX(T&A,T B){return A<B?A=B,:;}
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
namespace io{
const int SIZE = ( << ) + ;
char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - , c, qu[]; int f, qr;
#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
inline void flush (){fwrite (obuf, , oS - obuf, stdout);oS = obuf;}
inline void putc (char x){*oS ++ = x;if (oS == oT) flush ();}
template <class I>
inline void read(I &x) {for (f = , c = gc(); c < '' || c > ''; c = gc()) if (c == '-') f = -;
for (x = ; c <= '' && c >= ''; c = gc()) x = x * + (c & ); x *= f;}
template <class I>
inline void print (I x){
if (!x) putc (''); if (x < ) putc ('-'), x = -x;while(x) qu[++ qr] = x % + '', x /= ;while (qr) putc (qu[qr--]);}
struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io::read;
using io::putc;
using io::print;
const int N=+,INF=0x3f3f3f3f;
set<pii> s;
int h[N],fa[N][],fb[N][],to[N][],to2[N],disb[N];
int n,Q,T,m; inline void preprocess_the_bottom(){
set<pii>::iterator up,down;
int d0,d1,d2,d3,p0,p1,p2,p3;
m=__lg(n);
fa[n][]=fb[n][]=disb[n]=;to[n][]=to2[n]=n+;s.insert(make_pair(h[n],n));
for(register int i=n-;i;--i){
down=up=s.lower_bound(make_pair(h[i],));
d0=d1=d2=d3=,p0=p1=p2=p3=n+;
if(down!=s.begin())--down,d0=h[i]-(*down).dis,d0>1e9?(d0=):(p0=(*down).pos);//下侧第一
if(down!=s.begin())--down,d2=h[i]-(*down).dis,d2>1e9?(d2=):(p2=(*down).pos);//下侧第二
if(up!=s.end())d1=(*up).dis-h[i],d1>1e9?(d1=):(p1=(*up).pos);//上侧第一
if(up!=s.end()&&++up!=s.end())d3=(*up).dis-h[i],d3>1e9?(d3=):(p3=(*up).pos);//上侧第二
if(d0){
if(d1){//两侧都有
if(d1<d0){
disb[i]=d1,to2[i]=p1;
if(d3&&d3<d0)fa[i][]=d3,to[i][]=p3;//上侧第二为次近
else fa[i][]=d0,to[i][]=p0;//下侧第一为次近
}
else{
disb[i]=d0,to2[i]=p0;
if(d2&&d2<=d1)fa[i][]=d2,to[i][]=p2;//下侧第二为次近
else fa[i][]=d1,to[i][]=p1;//上侧第一为次近
}
}
else{//只有下侧
disb[i]=d0,to2[i]=p0;
fa[i][]=d2,to[i][]=p2;
}
}
else disb[i]=d1,to2[i]=p1,fa[i][]=d3,to[i][]=p3;//只有上侧或者两侧都没有
// dbg(i);_dbg(disb[i],to2[i]);_dbg(fa[i][0],to[i][0]);
s.insert(make_pair(h[i],i));
}
to2[n+]=n+;for(register int i=;i<=m;++i)to[n+][i]=n+;
} inline void preprocess(){
for(register int i=;i<=n;++i)fa[i][]=fa[i][],fb[i][]=disb[to[i][]],to[i][]=to2[to[i][]];
for(register int i=;i<=m;++i){
for(register int j=;j<=n;++j){
fa[j][i]=fa[j][i-]+fa[to[j][i-]][i-],fb[j][i]=fb[j][i-]+fb[to[j][i-]][i-];to[j][i]=to[to[j][i-]][i-];
fa[j][i]+0ll+fb[j][i]>1e9?(fa[j][i]=,fb[j][i]=,to[j][i]=n+):;
}
}
}
int xa,xb;
inline void Query(int x,int tot){
xa=xb=;
for(register int i=m;~i;--i)if(to[x][i]<=n&&fa[x][i]+fb[x][i]<=tot)tot-=fa[x][i]+fb[x][i],xa+=fa[x][i],xb+=fb[x][i],x=to[x][i];
}
int x,tot,p,q,ans;
int main(){//freopen("test.in","r",stdin);freopen("test.out","w",stdout);
read(n);for(register int i=;i<=n;++i)read(h[i]);
preprocess_the_bottom();preprocess();
read(Q);Query(,Q);p=xa,q=xb,ans=;
for(register int i=;i<=n;++i){
Query(i,Q);
if(!xb){if(!q)if(h[ans]<h[i])ans=i;continue;}
if(xa*1ll*q<xb*1ll*p)p=xa,q=xb,ans=i;
else if(xa*1ll*q==xb*1ll*p)if(h[ans]<h[i])ans=i;
}
print(ans);read(T);putc('\n');
for(register int i=;i<=T;++i){
read(x),read(tot);Query(x,tot);
print(xa),putc(' '),print(xb),putc('\n');
}
return ;
}

最新文章

  1. dynamic-css 动态 CSS 库,使得你可以借助 MVVM 模式动态生成和更新 css,从 js 事件和 css 选择器的苦海中脱离出来
  2. android清除本应用里的各种数据的方法
  3. 13.首先,编写一个类ChongZai,该类中有3个重载的方法void print();其次, 再编写一个主类来测试ChongZai类的功能。
  4. unity3d 三分钟实现简单的赛车漂移
  5. Android Services重点记录
  6. WPF之拖动项滚动条自滚动(当拖动项到达高度的边界时候滚动条自己可以上下滚动)
  7. 105、android:windowSoftInputMode属性详解
  8. plantuml
  9. maven项目:Invalid bound statement
  10. Jquery OR Js 实现图片预览
  11. windows中java读目录空格变成%20 处理方法
  12. jquery取对象数组元素的错误方式
  13. [置顶] RFS的web自动化验收测试——常见问题指引
  14. Nhibernate学习教程(2)-- 第一个NHibernate程序
  15. java-数据库连接,分层实现增删改查测试
  16. IOS 修改图片的地理位置信息
  17. dotNet core 应用部署至 centos(超详解附截图)
  18. 点到圆弧的距离(csu1503)+几何
  19. UPS不间断电源工作原理简述
  20. CentOS 6.5结合busybox完成自制Linux系统及远程登录和nginx安装测试

热门文章

  1. WebHook钩子
  2. Shell初学(八)linux下的ACL
  3. CSP 最大的矩形(201312-3)
  4. 从入门到自闭之Python随机模块
  5. linux增加swap大小
  6. CentOS7部署Tomcat服务器
  7. redis 学习(6)-- 集合类型
  8. 使用xpath爬取猫眼电影排行榜
  9. qt webengineview 设置背景颜色
  10. thinkjs-定时任务