[NOI2019] 弹跳
题目描述
跳蚤国有 \(n\) 座城市,分别编号为 \(1 - n\),\(1\) 号城市为首都。所有城市分布在一个\(w \times h\) 范围的网格上。每座城市都有一个整数坐标 \((x, y) (1 \leq x \leq w, 1 \leq y \leq h)\),不同城市的坐标不相同。
在跳蚤国中共有 \(m\) 个弹跳装置,分别编号为 \(1 - m\),其中 \(i\) 号弹跳装置位于 \(p_i\) 号城市,并具有参数 \(t_i, L_i, R_i, D_i, U_i\)。利用该弹跳装置,跳蚤可花费 \(t_i (t_i > 0)\) 个单位时间,从 \(p_i\) 号城市跳至坐标满足 \(L_i \leq x \leq R_i, D_i \leq y \leq U_i (1 \leq L_i \leq R_i \leq w, 1 \leq D_i \leq U_i \leq h)\) 的任意一座城市。需要注意的是,一座城市中可能存在多个弹跳装置,也可能没有弹跳装置。
由于城市间距离较远,跳蚤们必须依靠弹跳装置出行。具体来说,一次出行将经过
若干座城市,依次经过的城市的编号可用序列 \(a_0, a_1, \cdots , a_k\) 表示;在此次出行中,依次利用的弹跳装置的编号可用序列 \(b_1, b_2, \cdots , b_k\) 表示。其中每座城市可在序列 \(\{a_j\}\) 中出现任意次,每个弹跳装置也可在序列 \(\{b_j\}\) 中出现任意次,且满足,对于每个 \(j (1 \leq j \leq k)\),编号为 \(b_j\) 的弹跳装置位于城市 \(a_{j-1}\),且跳蚤能通过该弹跳装置跳至城市 \(a_j\)。我们称这是一次从城市 \(a_0\) 到城市 \(a_k\) 的出行,其进行了 \(k\) 次弹跳,共花费 \(\sum^k_{i=1} t_{b_{i}}\) 个单位时间。
现在跳蚤国王想知道,对于跳蚤国除首都(\(1\) 号城市)外的每座城市,从首都出发,到达该城市最少需要花费的单位时间。跳蚤国王保证,对每座城市,均存在从首都到它的出行方案。
\(1 \leq n \leq 70000 , 1 \leq m \leq 150000 , 1 \leq w, h \leq n , 1 \leq t_i \leq 10000\)。
尝试用 KDT 优化最短路。
将一整个矩形及其距离一起丢到堆里。那么每次从堆里面去除矩形之后,我们要找到所有矩形内还没有松驰过的点,可以用 KDT 维护。找到之后更改这个点能到的所有矩形的距离。
#include<bits/stdc++.h>
using namespace std;
const int N=1.5e5+5,INF=2e9;
typedef long long LL;
int n,m,w,h,l[N],r[N],u[N],d[N],t[N],rt;
vector<int>g[N];
int read()
{
int s=0;
char ch=getchar();
while(ch<'0'||ch>'9')
ch=getchar();
while(ch>='0'&&ch<='9')
s=s*10+ch-48,ch=getchar();
return s;
}
struct node{
int v;
LL w;
bool operator<(const node&n)const{
return w>n.w;
}
};
struct dian{
int x,y,id;
bool operator<(const dian&n)const{
return x<n.x;
}
};
priority_queue<node>q;
LL dis[N];
int cmp(dian a,dian b)
{
return a.y<b.y;
}
struct KDT{
int mny[N],mnx[N],mxy[N],mxx[N],c[N],s[N],idx,lc[N],rc[N];
dian a[N],id[N];
int build(int l,int r,int p)
{
if(l>r)
return 0;
int md=l+r>>1,x=++idx;
s[x]=1;
if(p)
nth_element(a+l,a+md+1,a+r+1);
else
nth_element(a+l,a+md+1,a+r+1,cmp);
lc[x]=build(l,md-1,p^1);
rc[x]=build(md+1,r,p^1);
mnx[x]=min({mnx[lc[x]],mnx[rc[x]],a[md].x});
mny[x]=min({mny[lc[x]],mny[rc[x]],a[md].y});
mxx[x]=max({mxx[lc[x]],mxx[rc[x]],a[md].x});
mxy[x]=max({mxy[lc[x]],mxy[rc[x]],a[md].y});
id[x]=a[md];
c[x]=c[lc[x]]+c[rc[x]]+s[x];
return x;
}
int find(int o,int l,int r,int d,int u)
{
if(!c[o])
return 0;
if(l>mxx[o]||r<mnx[o]||d>mxy[o]||u<mny[o])
return 0;
if(s[o])
{
if(l<=id[o].x&&id[o].x<=r&&d<=id[o].y&&id[o].y<=u)
{
s[o]=0;
c[o]=c[lc[o]]+c[rc[o]];
return id[o].id;
}
}
int k=find(lc[o],l,r,d,u);
if(!k)
k=find(rc[o],l,r,d,u);
c[o]=c[lc[o]]+c[rc[o]]+s[o];
return k;
}
}s;
void dijkstra()
{
q.push((node){0,0});
while(!q.empty())
{
int k=q.top().v,x;
LL w=q.top().w;
q.pop();
while(x=s.find(rt,l[k],r[k],d[k],u[k]))
{
dis[x]=w;
for(int j=0;j<g[x].size();j++)
q.push((node){g[x][j],w+t[g[x][j]]});
}
}
}
int main()
{
n=read(),m=read(),w=read(),h=read();
for(int i=1;i<=n;i++)
s.a[i].x=read(),s.a[i].y=read(),s.a[i].id=i;
l[0]=r[0]=s.a[1].x,d[0]=u[0]=s.a[1].y;
s.mnx[0]=s.mny[0]=INF;
rt=s.build(1,n,0);
for(int i=1,p;i<=m;i++)
scanf("%d%d%d%d%d%d",&p,t+i,l+i,r+i,d+i,u+i),g[p].push_back(i);
dijkstra();
for(int i=2;i<=n;i++)
printf("%lld\n",dis[i]);
}