Fence Obstacle Course[线段树+DP]

传送门

线段树维护从这个点可以掉到哪个栅栏

f[i][0] 表示从谷仓到该栅栏的最左端的距离

f[i][1] 表示到最右端

查询最左端掉下去的栅栏编号为a , 右端为b

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]))


#include
#include
#include
#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);
	}
}

 

你可能感兴趣的:(线段树,DP)