有一个1e8*1e8的网格图,保证每个格子是长度为100的正方形,在格点间行走时必须沿着水平或竖直方向,且只能在格点处拐弯
现在有n个直径为10的圆在不同格点上,保证同一行同一列最多只有一个圆。经过这些圆的时候必须绕着走
问从(x1,y1)走到(x2,y2)的最短路
n ≤ 2 ⋅ 1 0 5 n\le2\cdot10^5 n≤2⋅105
很显然我们只会朝着两个方向走,并且会尽量在圆处拐弯
先扔掉肯定走不到的圆,根据行列最多1的性质可知选出来的圆一定是x、y坐标单调的,那么跑一个lis就可以了
一开始直接忽略了走一个半圆的情况,看到样例才反应过来。。可以发现我们最多只会走一次半圆,会走半圆当且仅当每一行或每一列都有圆
#include
#include
#include
#include
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
#define fi first
#define se second
typedef std:: pair <int,int> pair;
const int INF=0x3f3f3f3f;
const double pi=acos(-1);
const int N=400005;
int f[N],s[N];
pair p[N],u[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
pair st,ed;
st.fi=read(),st.se=read();
ed.fi=read(),ed.se=read();
int n=read(),tot=0;
rep(i,1,n) p[i].fi=read(),p[i].se=read();
if (st.fi>ed.fi) {st.fi*=-1,ed.fi*=-1; rep(i,1,n) p[i].fi*=-1;}
if (st.se>ed.se) {st.se*=-1,ed.se*=-1; rep(i,1,n) p[i].se*=-1;}
rep(i,1,n) if (p[i].fi>=st.fi&&p[i].fi<=ed.fi&&p[i].se>=st.se&&p[i].se<=ed.se) {
u[++tot]=p[i];
}
std:: sort(u+1,u+tot+1);
int mx=0;
rep(i,1,tot) {
f[i]=std:: lower_bound(s+1,s+mx+1,u[i].se)-s;
if (f[i]>mx) s[mx=f[i]]=u[i].se;
else s[f[i]]=std:: min(s[f[i]],u[i].se);
}
double ans=100.0*(ed.fi-st.fi+ed.se-st.se)-(20-5*pi)*mx;
if (mx-1==std:: min(ed.fi-st.fi,ed.se-st.se)) ans+=5*pi;
printf("%.12lf", ans);
return 0;
}