题目描述
传送门
题解
对于矩形的每个顶点找到能到达的其他矩形边界上的点,然后将所有有用的点找出来。
先按照纵坐标排序,然后将纵坐标相同的点中相邻的点连边,注意在边界上的点需要特判,因为不能进入矩形。
然后按照横坐标排序,处理方式与纵坐标相同。
注意需要特判一下起点与终点的位置,因为有可能在矩形的边界上。
连完边,跑最短路即可。
代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<queue>
#define inf 1000000000
#define N 2000003
#define M 3020
#define LL long long
using namespace std;
struct data{
int x1,x2,y1,y2;
}a[M];
struct node{
int x,y,opt,pd,id;
}p[M*20];
int n,m,sx,sy,tx,ty,lx[M],ly[M],cntx,cnty,cnt;
int tot,point[N],nxt[N],v[N],can[N],T,st[N];
LL dis[N],c[N];
void add(int x,int y,LL z)
{
tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;
}
LL spfa(int s,int t)
{
queue<int> p;
memset(dis,127/3,sizeof(dis));
for (int i=1;i<=cnt;i++) can[i]=0;
p.push(s); can[s]=1; dis[s]=0;
while (!p.empty()){
int now=p.front(); p.pop();
for (int i=point[now];i;i=nxt[i])
if (dis[v[i]]>dis[now]+c[i]) {
dis[v[i]]=dis[now]+c[i];
if (!can[v[i]]) {
can[v[i]]=1;
p.push(v[i]);
}
}
can[now]=0;
}
return dis[t];
}
void findup(int now,int x,int y)
{
int mx=0; int pos=0;
for (int i=1;i<=n;i++) {
if (i==now) continue;
if(a[i].y1<=y&&a[i].y2>=y&&a[i].x2<x)
if (mx<a[i].x2) mx=max(mx,a[i].x2),pos=i;
}
if (a[pos].y1==y||a[pos].y2==y||mx==0) return;
p[++cnt].x=mx; p[cnt].y=y; p[cnt].opt=1;
}
void finddown(int now,int x,int y)
{
int mn=inf; int pos=0;
for (int i=1;i<=n;i++) {
if (i==now) continue;
if(a[i].y1<=y&&a[i].y2>=y&&a[i].x1>x)
if (mn>a[i].x1) mn=min(mn,a[i].x1),pos=i;
}
if (a[pos].y1==y||a[pos].y2==y||mn==inf) return;
p[++cnt].x=mn; p[cnt].y=y; p[cnt].opt=2;
}
void findl(int now,int x,int y)
{
int mx=0; int pos=0;
for (int i=1;i<=n;i++) {
if (i==now) continue;
if (a[i].x1<=x&&x<=a[i].x2&&a[i].y2<y)
if (mx<a[i].y2) mx=a[i].y2,pos=i;
}
if (a[pos].x1==x||a[pos].x2==x||mx==0) return;
p[++cnt].x=x; p[cnt].y=mx; p[cnt].opt=3;
}
void findr(int now,int x,int y)
{
int mn=inf; int pos=0;
for (int i=1;i<=n;i++) {
if (i==now) continue;
if (a[i].x1<=x&&x<=a[i].x2&&a[i].y1>y)
if (mn>a[i].y1) mn=a[i].y1,pos=i;
}
if (a[pos].x1==x||a[pos].x2==x||mn==inf) return;
p[++cnt].x=x; p[cnt].y=mn; p[cnt].opt=4;
}
int check(int x,int y,int x1,int y1,int x2,int y2)
{
if (x==x1&&y>y1&&y<y2) return 2;
if (x==x2&&y>y1&&y<y2) return 1;
if (y==y1&&x>x1&&x<x2) return 4;
if (y==y2&&x>x1&&x<x2) return 3;
return 0;
}
int cmp(node a,node b){
return a.x<b.x||a.x==b.x&&a.y<b.y;
}
int cmp1(node a,node b){
return a.y<b.y||a.y==b.y&&a.x<b.x;
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d",&T);
while (T--) {
scanf("%d%d%d%d",&sx,&sy,&tx,&ty);
cnt=0; tot=0; cntx=cnty=0;
lx[++cntx]=sx; lx[++cntx]=tx;
ly[++cnty]=sy; ly[++cnty]=ty;
memset(point,0,sizeof(point));
memset(p,0,sizeof(p));
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
if (a[i].x1>a[i].x2) swap(a[i].x1,a[i].x2);
if (a[i].y1>a[i].y2) swap(a[i].y1,a[i].y2);
lx[++cntx]=a[i].x1; lx[++cntx]=a[i].x2;
ly[++cnty]=a[i].y1; ly[++cnty]=a[i].y2;
}
sort(lx+1,lx+cntx+1); cntx=unique(lx+1,lx+cntx+1)-lx-1;
sort(ly+1,ly+cnty+1); cnty=unique(ly+1,ly+cnty+1)-ly-1;
sx=lower_bound(lx+1,lx+cntx+1,sx)-lx;
sy=lower_bound(ly+1,ly+cnty+1,sy)-ly;
tx=lower_bound(lx+1,lx+cntx+1,tx)-lx;
ty=lower_bound(ly+1,ly+cnty+1,ty)-ly;
++cnt; p[cnt].x=sx; p[cnt].y=sy; p[cnt].pd=1;
++cnt; p[cnt].x=tx; p[cnt].y=ty; p[cnt].pd=2;
for (int i=1;i<=n;i++) {
a[i].x1=lower_bound(lx+1,lx+cntx+1,a[i].x1)-lx;
a[i].y1=lower_bound(ly+1,ly+cnty+1,a[i].y1)-ly;
a[i].x2=lower_bound(lx+1,lx+cntx+1,a[i].x2)-lx;
a[i].y2=lower_bound(ly+1,ly+cnty+1,a[i].y2)-ly;
++cnt; p[cnt].x=a[i].x1; p[cnt].y=a[i].y1;
++cnt; p[cnt].x=a[i].x1; p[cnt].y=a[i].y2;
++cnt; p[cnt].x=a[i].x2; p[cnt].y=a[i].y1;
++cnt; p[cnt].x=a[i].x2; p[cnt].y=a[i].y2;
p[1].opt=max(p[1].opt,check(sx,sy,a[i].x1,a[i].y1,a[i].x2,a[i].y2));
p[2].opt=max(p[2].opt,check(tx,ty,a[i].x1,a[i].y1,a[i].x2,a[i].y2));
}
a[++n].x1=a[n].x2=tx; a[n].y1=a[n].y2=ty;
for (int i=1;i<=n-1;i++) {
findup(i,a[i].x1,a[i].y1); findup(i,a[i].x1,a[i].y2);
finddown(i,a[i].x2,a[i].y1); finddown(i,a[i].x2,a[i].y2);
findl(i,a[i].x1,a[i].y1); findl(i,a[i].x2,a[i].y1);
findr(i,a[i].x1,a[i].y2);
findr(i,a[i].x2,a[i].y2);
}
if(p[1].opt!=1)findup(0,sx,sy);
if(p[1].opt!=2)finddown(0,sx,sy);
if(p[1].opt!=3)findl(0,sx,sy);
if(p[1].opt!=4)findr(0,sx,sy);
if(p[2].opt!=1)findup(n,tx,ty);
if(p[2].opt!=2)finddown(n,tx,ty);
if(p[2].opt!=3)findl(n,tx,ty);
if(p[2].opt!=4)findr(n,tx,ty);
for (int i=1;i<=cnt;i++) p[i].id=i;
sort(p+1,p+cnt+1,cmp); int j=1;
for (int i=1;i<=cntx;i++) {
int top=0;
while (p[j].x==i&&j<=cnt) {
st[++top]=j;
j++;
}
if (top<=1) continue;
if (p[st[1]].opt!=4&&p[st[1]].pd!=2) add(p[st[1]].id,p[st[2]].id,ly[p[st[2]].y]-ly[p[st[1]].y]);
if (p[st[top]].opt!=3&&p[st[top]].pd!=2) add(p[st[top]].id,p[st[top-1]].id,ly[p[st[top]].y]-ly[p[st[top-1]].y]);
for (int j=2;j<=top-1;j++) {
if (p[st[j]].opt!=4&&p[st[j]].pd!=2) add(p[st[j]].id,p[st[j+1]].id,ly[p[st[j+1]].y]-ly[p[st[j]].y]);
if (p[st[j]].opt!=3&&p[st[j]].pd!=2) add(p[st[j]].id,p[st[j-1]].id,ly[p[st[j]].y]-ly[p[st[j-1]].y]);
}
}
j=1; int S,T;
sort(p+1,p+cnt+1,cmp1);
for (int i=1;i<=cnty;i++) {
int top=0;
while (p[j].y==i&&j<=cnt) {
st[++top]=j;
if (p[j].pd==1) S=p[j].id;
if (p[j].pd==2) T=p[j].id;
j++;
}
if (top<=1) continue;
if (p[st[1]].opt!=2&&p[st[1]].pd!=2) add(p[st[1]].id,p[st[2]].id,lx[p[st[2]].x]-lx[p[st[1]].x]);
if (p[st[top]].opt!=1&&p[st[top]].pd!=2) add(p[st[top]].id,p[st[top-1]].id,lx[p[st[top]].x]-lx[p[st[top-1]].x]);
for (int j=2;j<=top-1;j++) {
if (p[st[j]].opt!=2&&p[st[j]].pd!=2) add(p[st[j]].id,p[st[j+1]].id,lx[p[st[j+1]].x]-lx[p[st[j]].x]);
if (p[st[j]].opt!=1&&p[st[j]].pd!=2) add(p[st[j]].id,p[st[j-1]].id,lx[p[st[j]].x]-lx[p[st[j-1]].x]);
}
}
LL ans=spfa(S,T);
if (ans==dis[0]) printf("No Path\n");
else printf("%lld\n",spfa(S,T));
}
}