【JZOJ 省選模擬】6701.旅行(travel)

題目

Description

在這裏插入圖片描述
Input

在這裏插入圖片描述
Output
輸出到文件 travel.out 中。
一行一個整數,表示從起點到終點的最小路程。

Sample Input
樣例 1 輸入:
3 2 14 5 1
4 6 6 10
0 7 3 9
1 2 8 5

Sample Output
樣例 1 輸出:
20

Data Constraint
在這裏插入圖片描述

Hint
樣例解釋
路線爲 (2,14) − (0,14) − (0,1) − (5,1)。

思路

考試的時候一時腦抽忘了可以離散化,結果30暴力沒打完GG

首先我們yy一下可以得到,最優路徑有一個軸是單調的,就說不可能兩個軸都走遠路

那麼怎麼判斷呢?
考慮一個方案:假設sx<tx,sy<ty,我們要證明x軸單調
考慮不斷往y+1方向走,被攔着了就往x+1走。如果在到y=ty之前x>tx就證明x軸要往回走,所以就不單調。

那麼現在我們知道了單調,考慮怎麼求答案

還是假設sx<tx,sy<ty
我們從左往右走,遇到障礙就向上下走,然後順着建築拐彎
這樣我們最多會分出2*n條路線
直接爆搜是O(2N)
考慮每一列都用一個set維護,那麼時間複雜度就變成了O(nlogn)

代碼

#include<bits/stdc++.h>
using namespace std;
const int N=4e5+77;
int n,sx,sy,tx,ty,ans;
struct M
{
	int x1,y1,x2,y2;
} a[N];
int cmp(M a,M b)
{
	return a.x1<b.x1;
}
struct ND
{
	int x,d;
	ND(int _x=0,int _d=0){x=_x,d=_d;}
};
int operator<(ND a,ND b) {return a.x<b.x;}
set<int> s; 
int cnt;
set<int>::iterator it; 
set<ND> t;
set<ND>::iterator it0,it1;
struct line{int x,y,t;} p[N];
int cmpl(line a,line b){return a.x<b.x;}
void solve()
{
	cnt=0;
	cnt++,p[cnt].x=sx,p[cnt].y=sy,p[cnt].t=-1;
	cnt++,p[cnt].x=tx,p[cnt].y=ty,p[cnt].t=-2;
	for(int i=1; i<=n; i++) 
	{
		cnt++,p[cnt].x=a[i].x1,p[cnt].y=a[i].y1,p[cnt].t=1;
		cnt++,p[cnt].x=a[i].x2,p[cnt].y=a[i].y1,p[cnt].t=2;
	}
	sort(p+1,p+1+cnt,cmpl);
	s.clear(),s.insert(1e9); 
	int yjy=-2e9;
	for(int i=1; i<=cnt; i++)
	{
		if(p[i].t==1) s.insert(p[i].y); 
		if(p[i].t==2) s.erase(p[i].y);
		if(p[i].t==-1) yjy=sy;
		if(yjy>-2e9)
		{
			it=s.lower_bound(yjy);
			yjy=*it;
		}
		if(p[i].t==-2)
		{
			if(yjy<ty) return;
			break;
		}
	}
	sort(a+1,a+1+n,cmp);
	t.clear(),t.insert(ND(sy,0));
	for(int i=1; i<=n; i++) if(a[i].x1>sx)
	{
		if(a[i].x1>tx) break;
		it0=t.lower_bound(ND(a[i].y1,0));
		int mi0=2e9,mi1=2e9;
		while(it0!=t.end()&&(*it0).x<=a[i].y2)
		{
			mi0=min(mi0,(*it0).d+(*it0).x-a[i].y1);
			mi1=min(mi1,(*it0).d+a[i].y2-(*it0).x);
			it1=it0,it0++,t.erase(it1);
		}
		if(mi0<2e9)
		{
			t.insert(ND(a[i].y1,mi0));
			t.insert(ND(a[i].y2,mi1));
		}
	}
	for(it0=t.begin(); it0!=t.end(); it0++)
		ans=min(ans,abs((*it0).x-ty)+(*it0).d+tx-sx);	
}

int main()
{
	freopen("travel.in","r",stdin); freopen("travel.out","w",stdout);
	scanf("%d%d%d%d%d",&n,&sx,&sy,&tx,&ty);
	for(int i=1; i<=n; i++) scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
	int t1,t2;
	if(sx>tx) t1=-1; else t1=1;
	if(sy>ty) t2=-1; else t2=1;
	sx*=t1,tx*=t1,sy*=t2,ty*=t2;
	for(int i=1; i<=n; i++) 
	{
		a[i].x1*=t1,a[i].x2*=t1,a[i].y2*=t2,a[i].y1*=t2;
		if(a[i].x1>a[i].x2) swap(a[i].x1,a[i].x2);
		if(a[i].y1>a[i].y2) swap(a[i].y2,a[i].y1);
	}
	ans=2e9;
	solve();
	swap(sx,sy),swap(tx,ty);
	for(int i=1; i<=n; i++) swap(a[i].x1,a[i].y1),swap(a[i].x2,a[i].y2);
	solve();
	printf("%d",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章