【校内模拟】Speike(贪心)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/zxyoi_dreamer/article/details/102725076

简要题意:给出若干个不相交矩形,你不能经过这些矩形内部,但是可以经过边界,你只能走平行于坐标轴的路径。

问从 ( 0 , 0 ) (0,0) ( x t , 0 ) (x_t,0) 的最短距离。保证所有矩形被夹在 x = 0 x=0 x = x t x=x_t 两条直线之间。

题解:

仔细想一想就会发现很多性质。

首先在横坐标上我们不可能走回头路。

在纵坐标上我们可以只在撞墙的时候拐弯,这样可以忽略矩形的右端点,保留所有左侧的线段。

那么我们想要维护到达所有 y y 坐标的时候的最小代价。

再随便观察一下可以发现,直接用当前能够使用的 y y 坐标中离这个点最近的上下两个点来更新状态不会更劣。

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;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/102725076
今日推荐