[NOI2019][洛谷P5471]弹跳(dijkstra+KD-Tree)
题面
https://www.luogu.com.cn/problem/P5471
题解
前置知识:
- KD-Tree:https://oi-wiki.org/ds/kdt/
如果我们对于每一个弹跳装置i,从\(p_i\)到\(x \in [l_i,r_i],y \in [d_i,u_i]\)的所有点都连一条权值为\(t_i\)的边,再跑一遍dijkstra,这样的答案一定是正确的,可是这样除了空间不够外,还大大地超时了。
所以考虑使用KD-Tree来优化这一过程。dijkstra的步骤是,每次找出未访问点中,当前dis最小的点u,将u标记为已访问,再用u出发的边去更新其他的点。
可以将所有的点建出一棵KD-Tree,并在KD-Tree上维护全局未访问点的最小dis值以及取到该点的点u。用KD-Tree模拟dijkstra的过程,每次先取出维护的u和dis,然后对于u出发的每一个弹跳装置,相当于是一个矩形范围内的所有点,它们的dis值要和\(dis[u]+t_i\)取较小值。一般情况下这是无法做到的,但是由于本题只需要维护dis的最小值的特殊性,此时可以做到。
总时间复杂度\(O(n \sqrt{n})\)。
代码
#include<bits/stdc++.h>
using namespace std;
#define rg register
#define In inline
const int N = 7e4;
const int M = 15e4;
const int inf = 0x3f3f3f3f;
namespace IO{
In int read(){
int s = 0,ww = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();}
while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();}
return s * ww;
}
In void write(int x){
if(x < 0)putchar('-'),x = -x;
if(x > 9)write(x / 10);
putchar('0' + x % 10);
}
}
using namespace IO;
In void chkmax(int &x,int y){if(x < y)x = y;}
In void chkmin(int &x,int y){if(x > y)x = y;}
struct point{
int c[2];
}p[N+5];
int Dim;
int per[N+5];
In bool cmp(point a,point b){
return a.c[Dim] != b.c[Dim] ? a.c[Dim] < b.c[Dim] : a.c[Dim^1] < b.c[Dim^1];
}
In bool cmp1(int a,int b){
return cmp(p[a],p[b]);
}
In bool include(int L,int R,int l,int r){
return L <= l && r <= R;
}
In bool include(int L,int R,int D,int U,int l,int r,int d,int u){
return include(L,R,l,r) && include(D,U,d,u);
}
In bool its(int L,int R,int l,int r){
return !(R < l || r < L);
}
In bool its(int L,int R,int D,int U,int l,int r,int d,int u){
return its(L,R,l,r) && its(D,U,d,u);
}
bool vis[N+5];
struct KDTree{
int cnt,s[N+5][2],m[N+5][2],lc[N+5],rc[N+5];
int dis[N+5],minn[N+5],ans[N+5],flag[N+5]; //当前节点对应的dis/当前子树中未访问点中最小的dis/取到当前子树最小dis的点/min标记
int idx[N+5]; //当前kdtree节点对应原来的第几个点
void pushdown(int u){
if(flag[u] == inf)return;
int l = lc[u],r = rc[u];
if(l){
chkmin(dis[l],flag[u]);
chkmin(flag[l],flag[u]);
chkmin(minn[l],flag[u]);
}
if(r){
chkmin(dis[r],flag[u]);
chkmin(flag[r],flag[u]);
chkmin(minn[r],flag[u]);
}
flag[u] = inf;
}
void pushup(int u){
minn[u] = vis[idx[u]] ? inf + 1 : dis[u],ans[u] = u;
if(lc[u] && !vis[idx[ans[lc[u]]]])if(minn[lc[u]] < minn[u])minn[u] = minn[lc[u]],ans[u] = ans[lc[u]];
if(rc[u] && !vis[idx[ans[rc[u]]]])if(minn[rc[u]] < minn[u])minn[u] = minn[rc[u]],ans[u] = ans[rc[u]];
}
int build(int l,int r,int dim){
if(l > r)return 0;
int u = ++cnt;
int mid = (l + r) >> 1;
Dim = dim;
nth_element(per + l,per + mid,per + r + 1,cmp1);
idx[u] = per[mid];
dis[u] = per[mid] == 1 ? 0 : inf;
flag[u] = inf;
s[u][0] = m[u][0] = p[per[mid]].c[0];
s[u][1] = m[u][1] = p[per[mid]].c[1];
lc[u] = build(l,mid - 1,dim ^ 1);
rc[u] = build(mid + 1,r,dim ^ 1);
int L = lc[u],R = rc[u];
if(L){
chkmax(s[u][0],s[L][0]);chkmin(m[u][0],m[L][0]);
chkmax(s[u][1],s[L][1]);chkmin(m[u][1],m[L][1]);
}
if(R){
chkmax(s[u][0],s[R][0]);chkmin(m[u][0],m[R][0]);
chkmax(s[u][1],s[R][1]);chkmin(m[u][1],m[R][1]);
}
pushup(u);
return u;
}
void ud1(int u,int i,int dim){ //标记已使用
if(idx[u] == i){
pushdown(u);
pushup(u);
return;
}
pushdown(u);
Dim = dim;
if(cmp(p[i],p[idx[u]]))ud1(lc[u],i,dim ^ 1);
else ud1(rc[u],i,dim ^ 1);
pushup(u);
}
void ud2(int u,int ql,int qr,int qd,int qu,int x){ //区域与目标值取min
if(flag[u] <= x)return;
if(include(ql,qr,qd,qu,m[u][0],s[u][0],m[u][1],s[u][1])){
chkmin(minn[u],x);
chkmin(flag[u],x);
chkmin(dis[u],x);
return;
}
if(include(ql,qr,qd,qu,p[idx[u]].c[0],p[idx[u]].c[0],p[idx[u]].c[1],p[idx[u]].c[1]))
chkmin(dis[u],x);
pushdown(u);
int L = lc[u],R = rc[u];
if(L && its(m[L][0],s[L][0],m[L][1],s[L][1],ql,qr,qd,qu))ud2(L,ql,qr,qd,qu,x);
if(R && its(m[R][0],s[R][0],m[R][1],s[R][1],ql,qr,qd,qu))ud2(R,ql,qr,qd,qu,x);
pushup(u);
}
In void query(int &u,int &d){
u = idx[ans[1]],d = minn[1];
}
}T;
struct equip{
int t,l,r,d,u;
}e[M+5];
vector<int>v[N+5];
int ans[N+5];
int n,m,w,h;
void dij(){
memset(ans,0x3f,sizeof(ans));
ans[1] = 0;
for(rg int i = 1;i <= n;i++){
int u,d;
T.query(u,d);
ans[u] = d;
for(rg int j = 0;j < v[u].size();j++){
int id = v[u][j];
T.ud2(1,e[id].l,e[id].r,e[id].d,e[id].u,d + e[id].t);
}
vis[u] = 1;
T.ud1(1,u,0);
}
}
int main(){
n = read(),m = read(),w = read(),h = read();
for(rg int i = 1;i <= n;i++)p[i].c[0] = read(),p[i].c[1] = read();
for(rg int i = 1;i <= n;i++)per[i] = i;
T.build(1,n,0);
for(rg int i = 1;i <= m;i++){
int p = read();
v[p].push_back(i);
e[i].t = read(),e[i].l = read(),e[i].r = read(),e[i].d = read(),e[i].u = read();
}
dij();
for(rg int i = 2;i <= n;i++)write(ans[i]),putchar('\n');
return 0;
}