[loj3180]天桥
当离开天桥\(A\)时,对其分类讨论:
-
直接进入另一段天桥\(B\),此时位于\(A,B\)的公共端点
-
向上经过另一段天桥\(B\),若该点不为\(B\)端点,则考虑调整
具体的,不断撤回上一步,直至当前建筑高度\(\ge B\)或回到起点
若为前者,显然此时在\(B\)范围内,不妨直接从该处进入\(B\)
若为后者,则两者间建筑均\(<B\),其即为起点某侧第一个\(\ge B\)的建筑
-
向下经过另一段天桥\(B\),若该点不为\(A\)端点,可以类似的从后往前调整
综上,仅需考虑以下几类关键点:
- 起点、终点、天桥的端点
- 对于某天桥,起点/终点左右两侧第一个$\ge $其的建筑处
- 上述点下方第一个有天桥经过的点
点数和边数均为为\(O(m)\),时间复杂度为\(O(n+m\log m)\)
#include<bits/stdc++.h>
using namespace std;
#define L (k<<1)
#define R (L+1)
#define mid (l+r>>1)
typedef long long ll;
const int N=100005,M=10000000;
int n,m,V,st,ed,X[N],y[N],l[N],r[N],h[N],H[N];
vector<int>v[N],vq[N],vu[N];
vector<pair<int,int> >v0;
vector<pair<int,int> >::iterator it;
unordered_map<int,int>id[N];
namespace Seg1{
int f[N<<2];
void build(int k,int l,int r){
if (l==r)f[k]=y[l];
else{
build(L,l,mid),build(R,mid+1,r);
f[k]=max(f[L],f[R]);
}
}
int findL(int k,int l,int r,int x,int y){
if ((l>x)||(f[k]<y))return 0;
if (l==r)return l;
int ans=findL(R,mid+1,r,x,y);
return (ans ? ans : findL(L,l,mid,x,y));
}
int findR(int k,int l,int r,int x,int y){
if ((r<x)||(f[k]<y))return 0;
if (l==r)return l;
int ans=findR(L,l,mid,x,y);
return (ans ? ans : findR(R,mid+1,r,x,y));
}
};
namespace Seg2{
int f[N<<2];
void update(int k,int l,int r,int x,int y,int z){
if ((l>y)||(x>r))return;
if ((x<=l)&&(r<=y)){f[k]=z;return;}
if (f[k])f[L]=f[R]=f[k],f[k]=0;
update(L,l,mid,x,y,z),update(R,mid+1,r,x,y,z);
}
int query(int k,int l,int r,int x){
if (f[k])return f[k];
if (l==r)return 0;
if (x<=mid)return query(L,l,mid,x);
return query(R,mid+1,r,x);
}
};
namespace Graph{
int E,head[M],vis[M];ll d[M];
struct List{int nex,to,len;}e[M];
priority_queue<pair<ll,int> >q;
void init(){
memset(head,-1,sizeof(head));
}
void add(int x,int y,int z){
e[E]=List{head[x],y,z},head[x]=E++;
e[E]=List{head[y],x,z},head[y]=E++;
}
ll dijkstra(){
memset(d,0x3f,sizeof(d));
d[st]=0,q.push(make_pair(0,st));
while (!q.empty()){
int k=q.top().second;q.pop();
if (vis[k])continue;
vis[k]=1;
for(int i=head[k];i!=-1;i=e[i].nex)
if (d[e[i].to]>d[k]+e[i].len){
d[e[i].to]=d[k]+e[i].len;
q.push(make_pair(-d[e[i].to],e[i].to));
}
}
return (d[ed]==d[0] ? -1 : d[ed]);
}
};
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d%d",&X[i],&y[i]);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&l[i],&r[i],&h[i]);
l[i]++,r[i]++;
}
scanf("%d%d",&st,&ed);
st++,ed++;
if (st>ed)swap(st,ed);
memcpy(H,h,sizeof(H));
sort(H+1,H+m+1);
for(int i=1;i<=m;i++)h[i]=lower_bound(H+1,H+m+1,h[i])-H;
Seg1::build(1,1,n);
for(int i=1;i<=m;i++){
vq[h[i]].push_back(l[i]);
vq[h[i]].push_back(r[i]);
if ((l[i]<st)&&(st<r[i])){
int x=Seg1::findL(1,1,n,st,H[h[i]]),y=Seg1::findR(1,1,n,st,H[h[i]]);
if ((x)&&(x>l[i]))vq[h[i]].push_back(x);
if ((y)&&(y<r[i]))vq[h[i]].push_back(y);
}
if ((l[i]<ed)&&(ed<r[i])){
int x=Seg1::findL(1,1,n,ed,H[h[i]]),y=Seg1::findR(1,1,n,ed,H[h[i]]);
if ((x)&&(x>l[i]))vq[h[i]].push_back(x);
if ((y)&&(y<r[i]))vq[h[i]].push_back(y);
}
}
id[st][0]=++V,id[ed][0]=++V;
v[st].push_back(0),v[ed].push_back(0);
for(int i=1;i<=m;i++){
sort(vq[i].begin(),vq[i].end());
vq[i].resize(unique(vq[i].begin(),vq[i].end())-vq[i].begin());
for(int j:vq[i])id[j][i]=++V,v[j].push_back(i);
}
for(int i=1;i<=m;i++)vu[h[i]].push_back(i);
for(int i=1;i<=m;i++){
for(int j:vq[i]){
int x=Seg2::query(1,1,n,j);
if ((x)&&(!id[j][x])){
id[j][x]=++V;
v[j].push_back(x);
}
}
for(int j:vu[i])Seg2::update(1,1,n,l[j],r[j],i);
}
for(int i=1;i<=n;i++)sort(v[i].begin(),v[i].end());
for(int i=1;i<=m;i++)vq[i].clear();
for(int i=1;i<=n;i++)
for(int j:v[i])vq[j].push_back(i);
Graph::init();
for(int i=1;i<=n;i++){
if (v[i].empty())continue;
for(int j=1;j<v[i].size();j++){
int x=v[i][j],y=v[i][j-1];
Graph::add(id[i][x],id[i][y],H[x]-H[y]);
}
}
for(int i=1;i<=m;i++){
v0.clear();
for(int j:vu[i])v0.push_back(make_pair(l[j],r[j]));
sort(v0.begin(),v0.end());
for(int j=1;j<vq[i].size();j++){
int x=vq[i][j],y=vq[i][j-1];
it=lower_bound(v0.begin(),v0.end(),make_pair(y+1,0));
if ((it==v0.begin())||((*--it).second<x))continue;
Graph::add(id[x][i],id[y][i],X[x]-X[y]);
}
}
st=id[st][0],ed=id[ed][0];
printf("%lld\n",Graph::dijkstra());
return 0;
}