传送门
线段树维护从这个点可以掉到哪个栅栏
f[i][0] 表示从谷仓到该栅栏的最左端的距离
f[i][1] 表示到最右端
查询最左端掉下去的栅栏编号为a , 右端为b
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 100005
#define M N*2
using namespace std;
int val[M<<2],n,s,f[N][2],x1[N],x2[N];
void Pushdown(int x){
if(val[x]) {val[x<<1]=val[x<<1|1]=val[x]; val[x]=0;}
}
int quary(int x,int l,int r,int pos){
if(l==r){return val[x];}
Pushdown(x);
int mid=l+r>>1;
if(pos<=mid) return quary(x<<1,l,mid,pos);
else return quary(x<<1|1,mid+1,r,pos);
}
void update(int x,int l,int r,int L,int R,int v){
if(L<=l && r<=R){val[x]=v; return;}
Pushdown(x);
int mid=l+r>>1;
if(L<=mid) update(x<<1,l,mid,L,R,v);
if(R>mid) update(x<<1|1,mid+1,r,L,R,v);
}
int main(){
while(~scanf("%d%d",&n,&s)){
memset(val,0,sizeof(val)); s+=N; x1[0]=x2[0]=N;
for(int i=1;i<=n;i++){
scanf("%d%d",&x1[i],&x2[i]);
x1[i] += N , x2[i] += N;
int a=quary(1,1,M,x1[i]) , b=quary(1,1,M,x2[i]);
f[i][0] = min(f[a][0]+abs(x1[a]-x1[i]) , f[a][1]+abs(x2[a]-x1[i]));
f[i][1] = min(f[b][0]+abs(x1[b]-x2[i]) , f[b][1]+abs(x2[b]-x2[i]));
update(1,1,M,x1[i],x2[i],i);
}int ans=min(f[n][0]+abs(x1[n]-s),f[n][1]+abs(x2[n]-s));
printf("%d\n",ans);
}
}