题目
题目描述
跳蚤国有 nn 座城市,分别编号为 1 - n1−n,11 号城市为首都。所有城市分布在一个w \times hw×h 范围的网格上。每座城市都有一个整数坐标 (x, y) (1 \leq x \leq w, 1 \leq y \leq h)(x,y)(1≤x≤w,1≤y≤h),不同城市的坐标不相同。
在跳蚤国中共有 mm 个弹跳装置,分别编号为 1 - m1−m,其中 ii 号弹跳装置位于 p_ip
i
号城市,并具有参数 t_i, L_i, R_i, D_i, U_it
i
,L
i
,R
i
,D
i
,U
i
。利用该弹跳装置,跳蚤可花费 t_i (t_i > 0)t
i
(t
i
- 个单位时间,从 p_ip
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)L
i
≤x≤R
i
,D
i
≤y≤U
i
(1≤L
i
≤R
i
≤w,1≤D
i
≤U
i
≤h) 的任意一座城市。需要注意的是,一座城市中可能存在多个弹跳装置,也可能没有弹跳装置。
由于城市间距离较远,跳蚤们必须依靠弹跳装置出行。具体来说,一次出行将经过 若干座城市,依次经过的城市的编号可用序列 a_0, a_1, \cdots , a_ka
0
,a
1
,⋯,a
k
表示;在此次出行中,依次利用的弹跳装置的编号可用序列 b_1, b_2, \cdots , b_kb
1
,b
2
,⋯,b
k
表示。其中每座城市可在序列 {a_j}{a
j
} 中出现任意次,每个弹跳装置也可在序列 {b_j}{b
j
} 中出现任意次,且满足,对于每个 j (1 \leq j \leq k)j(1≤j≤k),编号为 b_jb
j
的弹跳装置位于城市 a_{j-1}a
j−1
,且跳蚤能通过该弹跳装置跳至城市 a_ja
j
。我们称这是一次从城市 a_0a
0
到城市 a_ka
k
的出行,其进行了 kk 次弹跳,共花费 \sum^k_{i=1} t_{b_{i}}∑
i=1
k
t
b
i
个单位时间。
现在跳蚤国王想知道,对于跳蚤国除首都(11 号城市)外的每座城市,从首都出发,到达该城市最少需要花费的单位时间。跳蚤国王保证,对每座城市,均存在从首都到它的出行方案。
输入格式
第一行包含四个整数 n, m,w, hn,m,w,h,变量的具体意义见题目描述。
接下来 nn 行,第 ii 行包含两个整数 x_i, y_ix
i
,y
i
,表示 ii 号城市的坐标。
接下来 mm 行,第 ii 行包含六个整数 p_i, t_i, L_i, R_i, D_i, U_ip
i
,t
i
,L
i
,R
i
,D
i
,U
i
,分别表示 ii 号弹跳装置所在的城市编号、弹跳所需的时间、可到达的矩形范围。这些整数的具体意义见题目描述。
输出格式
输出 n - 1n−1 行,第 ii 行包含一个整数,表示从跳蚤国首都到 i + 1i+1 号城市最少需要花费的单位时间。
输入输出样例
输入 #1复制
5 3 5 5
1 1
3 1
4 1
2 2
3 3
1 123 1 5 1 5
1 50 1 5 1 1
3 10 2 2 2 2
输出 #1复制
50
50
60
123
说明/提示
对于所有测试点和样例满足:
1 \leq n \leq 70000 , 1 \leq m \leq 150000 , 1 \leq w, h \leq n , 1 \leq t_i \leq 100001≤n≤70000,1≤m≤150000,1≤w,h≤n,1≤t
i
≤10000。
每个测试点的具体限制见下表。
测试点编号 1\le n\le1≤n≤ 1\le m\le1≤m≤ 特殊限制
1\sim81∼8 100100 100100 无
9\sim139∼13 5\times 10^45×10
4
10^510
5
每个弹跳装置恰好可达一座城市,且 L_i=R_iL
i
=R
i
,D_i=U_iD
i
=U
i
14\sim1814∼18 5\times 10^45×10
4
10^510
5
h=1h=1
19\sim2219∼22 2.5\times 10^42.5×10
4
5\times 10^45×10
4
无
23\sim2523∼25 7\times 10^47×10
4
1.5\times 10^51.5×10
5
无
思路
考虑dijkstra的过程:维护一个点集,每一次取出点集里到源点最近的点,用它去更新其他点到源点的距离,然后删除这个点。
那么我们就相当于要维护一个二维棋盘(格子上就是它到源点的距离),并支持以下的操作:
查询全局最小的点
更新子矩阵里所有格子上的值
删除某一个格子
大概就是一个kdtree吧。。。更新子矩阵就像线段树那样放标记就行了,删除的时候像替罪羊树那样懒惰删除。
代码
#include <bits/stdc++.h>
#define N 70005
#define M 150005
#define getchar nc
using namespace std;
int n,m,w,h;
int px[N],py[N];
int P[M],T[M],L[M],R[M],D[M],U[M];
set<pair<int,int> > s[N<<2];
vector<int> nv[N];
struct node{
int dis,pos;
bool operator < (const node &x) const{
return x.dis<dis;
}
};
priority_queue<node> q;
int dis[N+M],vis[N+M];
void modify(register int x,register int l,register int r,register int id)
{
s[x].insert(make_pair(py[id],id));
if(l==r)
return;
int mid=l+r>>1;
if(px[id]<=mid)
modify(x<<1,l,mid,id);
else
modify(x<<1|1,mid+1,r,id);
}
void change(register int x,register int l,register int r,register int id)
{
if(L[id]<=l&&r<=R[id])
{
set<pair<int,int> >::iterator it;
while(19260817)
{
it=s[x].lower_bound(make_pair(D[id],-1));
if(it==s[x].end()||it->first>U[id])
break;
int to=it->second;
if(dis[to]>dis[id+n])
{
dis[to]=dis[id+n];
q.push((node){dis[to],to});
}
s[x].erase(it);
}
return;
}
int mid=l+r>>1;
if(L[id]<=mid)
change(x<<1,l,mid,id);
if(R[id]>mid)
change(x<<1|1,mid+1,r,id);
}
int main()
{
n=read(),m=read(),w=read(),h=read();
for(register int i=1;i<=n;++i)
{
px[i]=read(),py[i]=read();
if(i!=1)
modify(1,1,w,i);
}
for(register int i=1;i<=m;++i)
{
P[i]=read(),T[i]=read(),L[i]=read(),R[i]=read(),D[i]=read(),U[i]=read();
nv[P[i]].push_back(i+n);
}
for(register int i=1;i<=n;++i)
dis[i]=1926081700,vis[i]=0;
dis[1]=0;
q.push((node){0,1});
while(!q.empty())
{
node tmp=q.top();
q.pop();
int x=tmp.pos;
if(vis[x])
continue;
vis[x]=1;
if(x<=n)
{
for(register int i=0;i<nv[x].size();++i)
{
int y=nv[x][i];
dis[y]=dis[x]+T[y-n];
q.push((node){dis[y],y});
}
}
else
change(1,1,w,x-n);
}
for(register int i=2;i<=n;++i)
write(dis[i]),puts("");
return 0;
}