题目大意:给定一个 \(W\times H\) 的平面,上面有 \(n\) 个城市 \((x_i,y_i)\),在 \(n\) 个城市中分布着 \(m\) 个装置,每一个装置都可以从城市 \(i\) 花费 \(t\) 时间到区域 \((D,L),(U,R)\) 内的另一城市 \((x_j,y_j)\)。现在从 \(1\) 号城市出发前往其他城市,求到每一个城市所需的最短时间
数据范围:\(1\leq L,R,U,D\leq W,H\leq N\leq 7\times 10^4,1\leq M\leq 1.5\times 10^5,t\leq 10000\)
题面大意求最短路,但是在一个平面上,逐个点处理时间空间上都不允许。
考虑 Dijkstra 算法,把边当做点处理放进队列。
遍历从 \(1\) 号节点出发的所有边,每抵达一个点,就把该点的所有边放进队列中,优先关键字:从开始走到当前选择的边,所需的时间。转移用树套树维护,外面的线段树维护横坐标,里面的维护纵坐标,查找一个区域的点在里面的树上二分,总复杂度 \(O(n\log^2 n+n\log n)\)。
代码:
#include<stdio.h>
#include<string.h>
#include<algo#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<set>
using namespace std;
template<class T>void read(T &x){
x=0; char c=getchar();
while(c<‘0‘||‘9‘<c)c=getchar();
while(‘0‘<=c&&c<=‘9‘){x=(x<<1)+(x<<3)+(c^48); c=getchar();}
}
typedef pair<int,int> pr;
#define mp make_pair
const int N=150007;
const int M=150007;
int n,m,W,H;
struct dvc{
int t,l,r,d,u;
}a[N];
int y[N],dis[N];
bool vis[N];
vector<int>e[N];
priority_queue< pr,vector<pr>,greater<pr> >q;
multiset<pr>s[M<<2];
void add(int l,int r,int p,int x,int i){
s[p].insert(mp(y[i],i));
if(l==r)return ;
int mid=(l+r)>>1;
if(x<=mid)add(l,mid,p<<1,x,i);
else add(mid+1,r,p<<1|1,x,i);
}
void upd(int l,int r,int p,int i,int d){
if(r<a[i].l||a[i].r<l)return ;
if(a[i].l<=l&&r<=a[i].r){
multiset<pr>::iterator it=s[p].lower_bound(mp(a[i].d,0)),tt;
int k;
while(it!=s[p].end()&&(*it).first<=a[i].u){
k=(*it).second;
if(!vis[k]){
vis[k]=1; dis[k]=d;
for(int i=0;i<e[k].size();i++)
q.push(pr(d+a[e[k][i]].t,e[k][i]));
}
tt=it; it++; s[p].erase(tt);
}
return ;
}
int mid=(l+r)>>1;
upd(l,mid,p<<1,i,d); upd(mid+1,r,p<<1|1,i,d);
}
int main(){
read(n); read(m); read(W); read(H);
int x;
for(int i=1;i<=n;i++){
read(x); read(y[i]);
add(1,W,1,x,i);
}
for(int i=1;i<=m;i++){
read(x); read(a[i].t);
read(a[i].l); read(a[i].r);
read(a[i].d); read(a[i].u);
e[x].push_back(i);
}
for(int i=0;i<e[1].size();i++)
q.push(pr(a[e[1][i]].t,e[1][i]));
vis[1]=1;
while(!q.empty()){
int i=q.top().second,d=q.top().first; q.pop();
upd(1,n,1,i,d);
}
for(int i=2;i<=n;i++)printf("%d\n",dis[i]);
return 0;
}
[Luogu P5471] NOI 2019 D2T1 弹跳
原文:https://www.cnblogs.com/opethrax/p/13026414.html