版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
简要题意:给出若干个不相交矩形,你不能经过这些矩形内部,但是可以经过边界,你只能走平行于坐标轴的路径。
问从 到 的最短距离。保证所有矩形被夹在 和 两条直线之间。
题解:
仔细想一想就会发现很多性质。
首先在横坐标上我们不可能走回头路。
在纵坐标上我们可以只在撞墙的时候拐弯,这样可以忽略矩形的右端点,保留所有左侧的线段。
那么我们想要维护到达所有 坐标的时候的最小代价。
再随便观察一下可以发现,直接用当前能够使用的 坐标中离这个点最近的上下两个点来更新状态不会更劣。
set或者map都可以维护。
然而我考场上看出了这个还是失智地去写线段树,卡常丢了5分
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
char c;T num;bool f=0;
while(!isdigit(c=gc()))f=c=='-';num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return f?-num:num;
}
inline int gi(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int N=5e5+7;
int n,xt;
struct seg{int t,l,r;}a[N];
inline bool cmp(cs seg &a,cs seg &b){return a.t<b.t;}
std::map<int,int> ma;
typedef std::map<int,int>::iterator iter;
#define fi first
#define se second
inline int calc(int y){
iter L=ma.upper_bound(y),R=L--;
if(R==ma.end())return L->se-L->fi+y;
if(R==ma.begin())return R->se+R->fi-y;
return std::min(L->se-L->fi+y,R->se+R->fi-y);
}
signed main(){
#ifdef zxyoi
freopen("speike.in","r",stdin);
#endif
n=gi(),xt=gi();
for(int re i=1;i<=n;++i){
int a=gi(),b=gi(),c=gi(),d=gi();
if(a>c)std::swap(a,c);
if(b>d)std::swap(b,d);
::a[i]=(seg){a,b,d};
}ma[0]=0;
std::sort(a+1,a+n+1,cmp);
for(int re i=1;i<=n;++i){
int t1=calc(a[i].l),t2=calc(a[i].r);
ma[a[i].l]=t1;ma[a[i].r]=t2;
std::map<int,int>::iterator L=ma.upper_bound(a[i].l);
std::map<int,int>::iterator R=ma.lower_bound(a[i].r);
ma.erase(L,R);
}cout<<xt+calc(0);
return 0;
}