分析
首先容易看出一个暴力,即每个点向能到达的点连边,然后最短路即可。
然而边数是 $\mathcal{O}(n^2)$ 级别的,我们需要优化连边。由于是向矩形范围内的点连边,所以考虑 KD-Tree 优化连边。
对于城市 $u$ 向矩形连的边,我们在 KD-Tree 上遍历:如果当前节点范围包含在矩形内,则 $u$ 直接向这个节点连边;如果当前节点范围与矩形无交,则直接返回;否则,如果这个节点表示的城市在矩形中则 $u$ 向这个节点表示的城市连边,然后递归处理左右儿子。
然后我们将 KD-Tree 上的所有节点向它的左右儿子和它表示的城市连 $0$ 边即可。
这样子空间会炸,所以我们可以不显式地连出边,而是使用 Dijkstra 并直接在 KD-Tree 上进行松弛。
有一个优秀的剪枝:当 KD-Tree 上某个节点的 $dis$ 小于等于当前松弛的 $dis$ 时可以直接返回,因为此时子树不可能被松弛。
代码
// ====================================
// author: M_sea
// website: https://m-sea-blog.com/
// ====================================
#include <bits/stdc++.h>
#define file(x) freopen(#x".in","r",stdin); freopen(#x".out","w",stdout)
using namespace std;
typedef long long ll;
int read() {
int X=0,w=1; char c=getchar();
while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
return X*w;
}
const int N=70000+10,M=150000+10;
int n,m,w,h,D;
struct point { int x[2],id; } p[N];
bool operator <(point a,point b) { return a.x[D]<b.x[D]; }
struct rec { int l,r,d,u,t; };
vector<rec> E[N];
#define ls(x) t[x].lc
#define rs(x) t[x].rc
int rt,tot=0,pos[N<<1];
struct node { point p; int lc,rc,mn[2],mx[2]; } t[N<<1];
void pushup(int o) {
for (int i=0;i<2;++i) {
t[o].mn[i]=t[o].mx[i]=t[o].p.x[i];
if (ls(o)) {
t[o].mn[i]=min(t[o].mn[i],t[ls(o)].mn[i]);
t[o].mx[i]=max(t[o].mx[i],t[ls(o)].mx[i]);
}
if (rs(o)) {
t[o].mn[i]=min(t[o].mn[i],t[rs(o)].mn[i]);
t[o].mx[i]=max(t[o].mx[i],t[rs(o)].mx[i]);
}
}
}
int build(int l,int r,int d) {
if (l>r) return 0;
int o=++tot,mid=(l+r)>>1;
D=d,nth_element(p+l,p+mid,p+r+1),t[o].p=p[mid],pos[p[mid].id]=o;
ls(o)=build(l,mid-1,d^1),rs(o)=build(mid+1,r,d^1);
pushup(o); return o;
}
bool outside(node t,int L,int R,int D,int U) {
return t.mx[0]<L||t.mn[0]>R||t.mx[1]<D||t.mn[1]>U;
}
bool inside(node t,int L,int R,int D,int U) {
return t.mn[0]>=L&&t.mx[0]<=R&&t.mn[1]>=D&&t.mx[1]<=U;
}
bool inside(point p,int L,int R,int D,int U) {
return p.x[0]>=L&&p.x[0]<=R&&p.x[1]>=D&&p.x[1]<=U;
}
struct Hnode { int u,d; };
bool operator <(Hnode a,Hnode b) { return a.d>b.d; }
priority_queue<Hnode> Q;
int dis[N<<1];
void relax(int v,int d) { if (d<dis[v]) dis[v]=d,Q.push((Hnode){v,d}); }
void relax(int o,int L,int R,int D,int U,int d) {
if (d>=dis[o+n]) return;
if (outside(t[o],L,R,D,U)) return;
if (inside(t[o],L,R,D,U)) { relax(o+n,d); return; }
if (inside(t[o].p,L,R,D,U)) relax(t[o].p.id,d);
if (ls(o)) relax(ls(o),L,R,D,U,d);
if (rs(o)) relax(rs(o),L,R,D,U,d);
}
void dijkstra() {
memset(dis,0x3f,sizeof(dis)),dis[1]=0,Q.push((Hnode){1,0});
while (!Q.empty()) {
int u=Q.top().u,d=Q.top().d; Q.pop();
if (dis[u]!=d) continue;
if (u<=n) {
for (auto i:E[u]) relax(rt,i.l,i.r,i.d,i.u,dis[u]+i.t);
} else {
relax(t[u-n].p.id,dis[u]);
if (ls(u-n)) relax(ls(u-n)+n,dis[u]);
if (rs(u-n)) relax(rs(u-n)+n,dis[u]);
}
}
}
int main() {
n=read(),m=read(),w=read(),h=read();
for (int i=1;i<=n;++i) p[i].x[0]=read(),p[i].x[1]=read(),p[i].id=i;
rt=build(1,n,0);
for (int i=1;i<=m;++i) {
int p=read(),t=read(),l=read(),r=read(),d=read(),u=read();
E[p].emplace_back((rec){l,r,d,u,t});
}
dijkstra();
for (int i=2;i<=n;++i) printf("%d\n",dis[i]);
return 0;
}