题面
牛牛被困在了一个房间里,他可以看到房间的出口,但是想要到达出口,需要经过 n n n 道闸门。我们可以根据这些闸门离牛牛的距离进行编号,离牛牛最近的闸门记为 1 1 1 号闸门,离牛牛最远的记为 n n n 号闸门。
牛牛每秒都可以选择前进到下一闸门,后退到上一闸门,或者原地不动(从起点到第一道闸门,从第 n n n 道闸门到出口的时间也是一秒)。
这些闸门在一些时刻是关闭的,无法通行,剩下的时刻是开启的,可以通行。
注意:如果牛牛所在的位置有一个闸门即将关闭,他在此时选择原地不动,就会被闸门夹到,变成牛排。牛牛想在不变成牛排的前提下走到出口,他想知道最短需要多少秒才能走到出口,如果他永远无法走到出口,输出 − 1 -1 −1。
在每一秒内,首先牛牛进行移动,然后闸门进行开/关的动作。
数据范围
20 % 20 \% 20% 的数据,满足 1 ≤ N , M ≤ 20 1 \leq N, M \leq 20 1≤N,M≤20。
60 % 60 \% 60% 的数据,满足 1 ≤ N , M ≤ 2000 1 \leq N, M \leq 2000 1≤N,M≤2000。
100 % 100 \% 100% 的数据,满足 1 ≤ N , M ≤ 100000 , 1 ≤ a ≤ N , 1 ≤ b ≤ c ≤ 1 0 9 1 \leq N, M \leq 100000,1 \leq a \leq N, 1 \leq b \leq c \leq 10^9 1≤N,M≤100000,1≤a≤N,1≤b≤c≤109。
题解
对于每一段不可走的区间,我们考虑其可走的区间。对于一段可走的区间,他可以向两边与他有交集部分的区间走,至于怎么判断有没有交集?由于区间不相交,将其按左端点排序,我们只需要判断其左端点在该区间内即可,还有一种情况,左端点在区间外,但是其右端点在区间内,由于这种区间最多只有一个,所以特判一下。由于左端点具有单调性,所以我们可以用二分查找。然后跑一遍最短路即可。
代码
#include<bits/stdc++.h>
#define inf 1<<50
#define ll long long
using namespace std;
const int N=4e5+10;
inline int read(){
int k=0,f=1;
char ch;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')k=k*10+ch-'0',ch=getchar();
return k*f;
}
ll n,m,cnt,ans=6e9;
bool v[N];
struct Node{
int a,b,id,dep;
};
bool cmp(const Node x,const Node y){return x.a<y.a;}
vector<ll > s[N];
vector<Node> qu[N],ck[N];
void puts(Node x){
cout<<x.a<<" "<<x.b<<" "<<x.id<<" "<<x.dep<<endl;
}
//int tot=1,ver[N*2],nxt[N*2],fst[N];
inline void prework(){
for(int i=1;i<=n;++i){
int L=1,R=2e9;
sort(qu[i].begin(),qu[i].end(),cmp);
Node CK;
for(int j=0;j<qu[i].size();++j){
CK.a=L,CK.b=qu[i][j].a-1,CK.id=++cnt,CK.dep=i;
if(qu[i][j].a>L)ck[i].push_back(CK);
L=qu[i][j].b+1;
}
CK.a=L,CK.b=R,CK.id=++cnt,CK.dep=i;
ck[i].push_back(CK);
qu[i].clear();
for(int j=0;j<ck[i].size();++j)qu[i].push_back(ck[i][j]);//,cout<<"FAQ "<<i<<" "<<j<<endl,puts(qu[i][j]);
}
for(int i=1;i<=n;++i){
//cout<<i<<" "<<qu[i].size()<<endl;
sort(qu[i].begin(),qu[i].end(),cmp);
for(int j=0;j<qu[i].size();++j){
//cout<<"qu "<<i<<" "<<j<<" ";puts(qu[i][j]);
s[i].push_back(qu[i][j].a);
}
sort(s[i].begin(),s[i].end());
}
s[0].push_back(1);
}
queue<Node > q;
ll dis[N*4];
inline void SPFA(){
memset(dis,0x3f,sizeof(dis));
//cout<<dis[0]<<endl;
Node p;
p.a=1;p.b=2e9,p.id=0,p.dep=0;
qu[0].push_back(p);v[0]=1;dis[0]=0;
q.push(p);
while(q.size()){
Node x=q.front();q.pop();
//cout<<"FAAAAA ";puts(x);cout<<"DIS "<<dis[x.id]<<endl;
int L=x.a,R=x.b,D=x.dep,P=x.id;v[P]=0;
if(D==n)continue;
int l1=-1,l2=-1,r1=-1,r2=-1;
l1=lower_bound(s[D+1].begin(),s[D+1].end(),L)-s[D+1].begin();
if(l1&&qu[D+1][l1-1].b>=L)l1--;
if(D)l2=lower_bound(s[D-1].begin(),s[D-1].end(),L)-s[D-1].begin();
if(l2&&D&&qu[D-1][l2-1].b>=L)l2--;
r1=upper_bound(s[D+1].begin(),s[D+1].end(),R+1)-s[D+1].begin()-1;
if(D)r2=upper_bound(s[D-1].begin(),s[D-1].end(),R+1)-s[D-1].begin()-1;//,cout<<"RRRR "<<r2<<" "<<D-1<<" "<<R<<" "<<endl;
//cout<<"L R "<<l1<<" "<<r1<<" "<<l2<<" "<<r2<<endl;
for(int j=l1;j<=r1&&l1>=0&&r1>=0;++j){
// puts(qu[D+1][j]);
ll P1=qu[D+1][j].id,L1=qu[D+1][j].a,R1=qu[D+1][j].b;
// cout<<"ck "<<dis[P]<<" "<<R1<<" "<<dis[P1]<<" "<<L1<<endl;
if(dis[P]>=R1)continue;
if(dis[P1]>max(dis[P]+1,L1)){
dis[P1]=max(dis[P]+1,L1);
if(!v[P1]){
//cout<<"ck "<<P1<<endl;
q.push(qu[D+1][j]);
v[P1]=1;
}
}
}
for(int j=l2;j<=r2&&l2>=0&&r2>=0;++j){
ll P2=qu[D-1][j].id,L2=qu[D-1][j].a,R2=qu[D-1][j].b;
if(dis[P]>=R2)continue;
if(dis[P2]>max(dis[P]+1,L2)){
dis[P2]=max(dis[P]+1,L2);
if(!v[P2]){
q.push(qu[D-1][j]);
v[P2]=1;
}
}
}
}
}
int main(){
n=read();m=read();
for(int i=1;i<=m;++i){
int c=read(),a=read(),b=read();
Node p1;
p1.a=a,p1.b=b,p1.id=i,p1.dep=c;
qu[c].push_back(p1);
// puts(p1);puts(p2);
}
prework();
SPFA();
for(int i=0;i<qu[n].size();++i){
ans=min(ans,dis[qu[n][i].id]+1);
}
if(ans==6e9)ans=-1;
printf("%d\n",ans);
return 0;
}