题意:
在一个平面坐标系里有 n n n个矩形障碍,我们只能沿着障碍的边界移动或沿着平行于坐标轴的位置移动
给出一个终点 ( x , 0 ) (x,0) (x,0)
问最少时间是多少
分析:
我们可以想到的,我们移动时横坐标一定是单调递增的,向右移动时如果遇到障碍,那肯定是往最靠近当前位置的边移动然后沿边走,如果没遇到障碍,那还等啥,接着走呀
因为如此,我们可以用线段树来维护离当前位置最近的边的位置进行转移
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<queue>
#define LL long long
using namespace std;
inline LL read()
{
LL s=0,f=1; char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') {
s=s*10+c-'0';c=getchar();}
return s*f;
}
struct node{
int a,b,c,d;
}s[500005];
int y[1000005];
bool cmp(node x,node y) {
return x.a<y.a;}
int g;
struct Tree{
int w[4000005];
void add(int k,int L,int R,int l,int r,int v)
{
if(l<=L&&R<=r) {
w[k]=v;return;}
int mid=(L+R)>>1;
if(l<=mid) add(k*2,L,mid,l,r,v);
if(r>mid) add(k*2+1,mid+1,R,l,r,v);
return;
}
void ask(int k,int L,int R,int p)
{
g=max(g,w[k]);
if(L==R) return;
int mid=(L+R)>>1;
if(p<=mid) ask(k*2,L,mid,p);
else ask(k*2+1,mid+1,R,p);
return;
}
}t;
int f[1000005][2];
int main()
{
// freopen("speike.in","r",stdin);
// freopen("speike.out","w",stdout);
int n=read(),xt=read(),len=0;
for(int i=1;i<=n;i++)
{
int a=read(),b=read(),c=read(),d=read();
if(a>c) swap(a,c); if(b>d) swap(b,d);
s[i]=(node){
a,b,c,d};
y[++len]=b;y[++len]=d;
}
y[++len]=0;
sort(y+1,y+1+len);
int m=unique(y+1,y+1+len)-y-1;
s[++n]=(node){
xt,0,xt,0};
sort(s+1,s+1+n,cmp);
for(int i=1;i<=n;i++)
{
int a=lower_bound(y+1,y+1+m,s[i].b)-y,b=lower_bound(y+1,y+1+m,s[i].d)-y;
g=0;t.ask(1,1,m,a);
f[i][0]=min(f[g][0]+abs(s[g].b-s[i].b),f[g][1]+abs(s[g].d-s[i].b));
g=0;t.ask(1,1,m,b);
f[i][1]=min(f[g][0]+abs(s[g].b-s[i].d),f[g][1]+abs(s[g].d-s[i].d ));
t.add(1,1,m,a,b,i);
}
cout<<f[n][0]+xt;
return 0;
}