2304: [Apio2011]寻路

2304: [Apio2011]寻路

Time Limit: 20 Sec   Memory Limit: 256 MB
Submit: 512   Solved: 162
[ Submit][ Status][ Discuss]

Description

TooDee是一块二维格子状的土地(就像著名的笛卡尔坐标系那样) ,在这里
生活着很多可爱的Dee。Dee是像蜜蜂一样的小动物,它们只在二维活动,而且
它们非常的文明开化。TooDee 的蜂窝和正常世界的蜂窝也是很不一样的,它们
是矩形的且它们的边平行于TooDee的地理坐标系,就是说矩形的边或者是东西
走向,或者是南北走向。 
因为 Dees 是很高级的生物,它们有很多固定的飞行轨道,这些轨道由一些
平行于坐标轴的线段组成,线段只会在经纬度都是整数的点相交。 Dee在TooDee
飞行时必须遵守以下规则(请记住TooDee中所有点的经纬度都是整数): 
1  如果当前在点(XS, YS), 则下步只能飞到四个邻点  (XS, YS – 1), (XS, YS + 1),   
(XS – 1, YS ), (XS + 1, YS ); 
2  不可以进入蜂巢; 
3  只能在蜂巢的角或者边上改变飞行方向; 
4  开始的时候可以向任何方向飞; 
今晚是公共财政大臣Deeficer的女儿的生日,她想尽早回家,请帮她找到最
快的回家路径。假设她每秒可以飞行一个单位的距离。

Input

每个测试点包含多组数据。 
输入的第一行包含一个整数T,表示测试数据的组数。接下来依次描述这T
组数据,相邻的两组之间使用一个空行分隔。测试数据不多于20组。 
对于每组数据,第一行包含4个整数 xs, ys, xt, yt,表示Deeficer 的办公室和
家的坐标分别为(xs, ys)和(xt, yt)。第二行包含一个整数n,表示蜂巢的个数。接下
来的n行描述所有的蜂巢,其中第 i行包含 4 个整数xi1,  yi1,  xi2,  yi2,表示第i个
蜂巢两个对角的坐标分别为(xi1, yi1)和(xi2, yi2)。 
任何两个蜂巢都不会相交,也不会接触(在角上也不会接触)。办公室和家
处在不同的位置。每个蜂巢的面积为正。

Output

对于每一组数据,输出一个整数,表示Deeficer 最快回家的时间(单位为秒),
如果她无法按规则回家,则输出“No Path”。

对于100%的测试数据,1 ≤ n ≤ 1000,所有坐标都是不超过10^9
的整数;

Sample Input

2

1 7 7 8
2
2 5 3 8
4 10 6 7

2 1 5 4
1
3 1 4 3

Sample Output

9
No Path

HINT

数据为国际加国内综合版

Source

[ Submit][ Status][ Discuss]

第一感觉就是最短路
好一点的搜索方案是把所有矩形的坐标离散化,这样全图剩下O(n^2)个点
本来以为这样可以过,,但是只能过60%的数据,,GG
n^2的点即使每个点只有四条边,也是不行啊。。。

好不容易找到正解,,
就是这样一张图。。对于从一个矩形起飞,最多造出12个有效点
这样点数瞬间降到O(n)级别,SPFA就能过啦


不过这时候找这些点就非常麻烦。。。
苟蒻的做法是想扫描线一样,一行一行/一列一列搞,在线段树中查询前驱or后缀之类
把需要新建的点扔到坐标系,和前驱and后缀连边
新建完点之后要注意哪些方向不能连
以及边角点和起始点要特判它一定是能走向四方。。
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int maxn = 2010;
const int dx[4] = {0,1,0,-1};
const int dy[4] = {1,0,-1,0};
typedef long long LL;
const LL INF = 1E15;
const int inf = 2139062143;
const int T = 8;

struct Event{
	int key,pos,typ;
	Event(){}
	Event(int key,int pos,int typ): key(key),pos(pos),typ(typ){}
	bool operator < (const Event &B) const{
		if (key < B.key) return 1;
		if (key > B.key) return 0;
		if (typ < B.typ) return 1;
		return 0;
	}
}E[maxn*T];

struct Point{
	int key,Num;
	Point(){}
	Point(int key,int Num): key(key),Num(Num){}
	bool operator < (const Point &B) const {return key < B.key;}
};

struct Edg{
	int to,w;
	Edg(){}
	Edg(int to,int w): to(to),w(w){}
};

int n,Ti,sx,sy,tx,ty,cx,cy,tox,toy,tot,ax[maxn],Mark[maxn][maxn]
	,cnt,Cnt,Begin,End,px1[maxn],py1[maxn],px2[maxn],py2[maxn],ay[maxn]
	,Left[maxn*T],Right[maxn*T],num[maxn][maxn],unable[maxn*20];
LL dis[maxn*20];
bool vis[maxn*20];

vector <Point> px[maxn];
vector <Point> py[maxn];
vector <Edg> v[maxn*20];
queue <int> Q;

int getint()
{
	char ch = getchar();
	int ret = 0,tmp = 1;
	while (ch < '0' || '9' < ch) {
		if (ch == '-') tmp = -1;
		ch = getchar();
	}
	while ('0' <= ch && ch <= '9')
		ret = ret*10 + ch - '0',ch = getchar();
	return ret*tmp;
}

void Work()
{
	cx = cy = 1;
	sort(ax + 1,ax + tox + 1);
	for (int i = 2; i <= tox; i++)
		if (ax[i] != ax[i-1])
			ax[++cx] = ax[i];
	sort(ay + 1,ay + toy + 1);
	for (int i = 2; i <= toy; i++)
		if (ay[i] != ay[i-1])
			ay[++cy] = ay[i];
	for (int i = 1; i <= n; i++) {
		px1[i] = lower_bound(ax + 1,ax + cx + 1,px1[i]) - ax;
		py1[i] = lower_bound(ay + 1,ay + cy + 1,py1[i]) - ay;
		px2[i] = lower_bound(ax + 1,ax + cx + 1,px2[i]) - ax;
		py2[i] = lower_bound(ay + 1,ay + cy + 1,py2[i]) - ay;
	}
	sx = lower_bound(ax + 1,ax + cx + 1,sx) - ax;
	sy = lower_bound(ay + 1,ay + cy + 1,sy) - ay;
	tx = lower_bound(ax + 1,ax + cx + 1,tx) - ax;
	ty = lower_bound(ay + 1,ay + cy + 1,ty) - ay;
}

void Add(int x,int y) {ax[++tox] = x; ay[++toy] = y;}
void Read()
{
	sx = getint();
	sy = getint();
	tx = getint();
	ty = getint();
	tox = toy = 0;
	Add(sx,sy);
	Add(tx,ty);
	n = getint();
	for (int i = 1; i <= n; i++) {
		px1[i] = getint();
		py1[i] = getint();
		px2[i] = getint();
		py2[i] = getint();
		if (px1[i] > px2[i]) swap(px1[i],px2[i]);
		if (py1[i] > py2[i]) swap(py1[i],py2[i]);
		Add(px1[i],py1[i]);
		Add(px2[i],py2[i]);
	}
}

void SPFA()
{
	for (int i = 1; i <= cnt; i++)
		dis[i] = INF,vis[i] = 0;
	Q.push(Begin);
	dis[Begin] = 0;
	vis[Begin] = 1;
	while (!Q.empty()) {
		int k = Q.front(); 
		vis[k] = 0; Q.pop();
		for (int i = 0; i < v[k].size(); i++) {
			int to = v[k][i].to;
			LL w = v[k][i].w;
			if (dis[to] > dis[k] + w) {
				dis[to] = dis[k] + w;
				if (vis[to]) continue;
				vis[to] = 1;
				Q.push(to);
			}
		}
	}
	if (dis[End] == INF) puts("No Path");
	else printf("%lld\n",dis[End]);
	for (int i = 1; i <= cnt; i++) v[i].clear();
}

int New(int x,int y,int WA)
{
	if (Mark[x][y] == Cnt) {
		if (WA == -1)
			unable[num[x][y]] = WA;
		return -1;
	}
	Mark[x][y] = Cnt;
	++cnt;
	px[x].push_back(Point(ay[y],cnt));
	py[y].push_back(Point(ax[x],cnt));
	unable[cnt] = WA;
	num[x][y] = cnt;
	return cnt;
}

void Add_Edgs()
{
	for (int i = 1; i <= cx; i++) {
		if (!px[i].size()) continue;
		sort(px[i].begin(),px[i].end());
		for (int j = 1; j < px[i].size(); j++) {
			int A = px[i][j-1].Num,B = px[i][j].Num;
			int w = px[i][j].key - px[i][j-1].key;
			if (unable[A] != 0) v[A].push_back(Edg(B,w));
			if (unable[B] != 2) v[B].push_back(Edg(A,w));
		}
		px[i].clear();
	}
	for (int i = 1; i <= cy; i++) {
		if (!py[i].size()) continue;
		sort(py[i].begin(),py[i].end());
		for (int j = 1; j < py[i].size(); j++) {
			int A = py[i][j-1].Num,B = py[i][j].Num;
			int w = py[i][j].key - py[i][j-1].key;
			if (unable[A] != 1) v[A].push_back(Edg(B,w));
			if (unable[B] != 3) v[B].push_back(Edg(A,w));
		}
		py[i].clear();
	}
}

void Modify(int o,int l,int r,int pos,int typ)
{
	if (l == r) {
		if (typ == 1) Left[o] = Right[o] = l;
		else Left[o] = inf,Right[o] = 0;
		return;
	}
	int mid = (l + r) >> 1;
	if (pos <= mid) Modify(o<<1,l,mid,pos,typ);
	else Modify(o<<1|1,mid + 1,r,pos,typ);
	Left[o] = min(Left[o<<1],Left[o<<1|1]);
	Right[o] = max(Right[o<<1],Right[o<<1|1]);
}

int Lower(int o,int l,int r,int ql,int qr)
{
	if (ql > qr) return inf;
	if (ql <= l && r <= qr) return Left[o];
	int mid = (l + r) >> 1,ret = inf;
	if (ql <= mid) ret = Lower(o<<1,l,mid,ql,qr);
	if (ret < inf) return ret;
	if (qr > mid) ret = Lower(o<<1|1,mid+1,r,ql,qr);
	return ret;
}

int Upper(int o,int l,int r,int ql,int qr)
{
	if (ql > qr) return 0;
	if (ql <= l && r <= qr) return Right[o];
	int mid = (l + r) >> 1,ret = 0;
	if (qr > mid) ret = Upper(o<<1|1,mid+1,r,ql,qr);
	if (ret) return ret;
	if (ql <= mid) ret = Upper(o<<1,l,mid,ql,qr);
	return ret;
}

void Pre_Clear()
{
	sort(E + 1,E + tot + 1);
	memset(Left,127,sizeof(Left));
	memset(Right,0,sizeof(Right));
}

void Build()
{
	cnt = tot = 0; ++Cnt;
	Begin = New(sx,sy,-1); 
	End = New(tx,ty,-1); 
	for (int i = 1; i <= n; i++) {
		E[++tot] = Event(py1[i],px1[i],1);
		E[++tot] = Event(py2[i] + 1,px1[i],2);
		E[++tot] = Event(py1[i],px1[i],5);
		E[++tot] = Event(py2[i],px1[i],3);
		E[++tot] = Event(py1[i],px2[i],1);
		E[++tot] = Event(py2[i] + 1,px2[i],2);
		E[++tot] = Event(py1[i],px2[i],6);
		E[++tot] = Event(py2[i],px2[i],4);
	}
	E[++tot] = Event(sy,sx,3);
	E[++tot] = Event(sy,sx,6);
	E[++tot] = Event(ty,tx,3);
	E[++tot] = Event(ty,tx,6);
	Pre_Clear();
	for (int i = 1; i <= tot; i++) {
		if (E[i].typ == 1) Modify(1,1,cx,E[i].pos,1);
		else if (E[i].typ == 2) Modify(1,1,cx,E[i].pos,-1);
		else if (E[i].typ == 3 || E[i].typ == 5) {
			New(E[i].pos,E[i].key,-1);
			int po = Upper(1,1,cx,1,E[i].pos - 1);
			if (po) New(po,E[i].key,3);
		}
		else {
			New(E[i].pos,E[i].key,-1);
			int po = Lower(1,1,cx,E[i].pos + 1,cx);
			if (po < inf) New(po,E[i].key,1);
		}
	}
	
	tot = 0;
	for (int i = 1; i <= n; i++) {
		E[++tot] = Event(px1[i],py1[i],1);
		E[++tot] = Event(px2[i] + 1,py1[i],2);
		E[++tot] = Event(px1[i],py1[i],5);
		E[++tot] = Event(px2[i],py1[i],6);
		E[++tot] = Event(px1[i],py2[i],1);
		E[++tot] = Event(px2[i] + 1,py2[i],2);
		E[++tot] = Event(px1[i],py2[i],3);
		E[++tot] = Event(px2[i],py2[i],4);
	}
	E[++tot] = Event(sx,sy,3);
	E[++tot] = Event(sx,sy,6);
	E[++tot] = Event(tx,ty,3);
	E[++tot] = Event(tx,ty,6);
	Pre_Clear();
	for (int i = 1; i <= tot; i++) {
		if (E[i].typ == 1) Modify(1,1,cy,E[i].pos,1);
		else if (E[i].typ == 2) Modify(1,1,cy,E[i].pos,-1);
		else if (E[i].typ == 5 || E[i].typ == 6) {
			New(E[i].key,E[i].pos,-1);
			int po = Upper(1,1,cy,1,E[i].pos - 1);
			if (po) New(E[i].key,po,2);
		}
		else {
			New(E[i].key,E[i].pos,-1);
			int po = Lower(1,1,cy,E[i].pos + 1,cy);
			if (po < inf) New(E[i].key,po,0);
		}
	}
	Add_Edgs();
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	cin >> Ti;
	while (Ti--) {
		Read();
		Work();
		Build();
		SPFA();
	}
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值