CF383B Solution
题解
分行考虑,每一行都被火山截断为若干个区间(由于\(n\)数据范围较大,只考虑有火山的行)。如果上一行不存在与当前区间有交集的区间,则将其删去,判断最后是否留有可行区间即可。
具体实现:将每行的区间放入一个集合之中,对于一个区间\([l,r]\),二分上一行中第一个左端点\(\ge l\)的区间和最后一个左端点\(<l\)的区间,可行区间为交集左端点最小值到\(r\)。如果存在可行区间,并且第\(n\)行有火山且\((n,n)\)被可行区间覆盖,或第\(n\)行没有火山,则可以到达,距离为\(2n-2\)。否则输出-1。
代码
#include<bits/stdc++.h>
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
using namespace std;
const int N=1e5+10;
pii a[N];
vector<pii > seg,tmp;
inline int read()
{
int s=0,w=1; char ch=getchar();
while(ch<'0' || ch>'9') {if(ch=='-') w=-1; ch=getchar();}
while(ch>='0' && ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
int main()
{
int n=read(),m=read(),lst=0;
for(int i=1;i<=m;i++) a[i].first=read(),a[i].second=read();
sort(a+1,a+m+1);
seg.pb(mp(1,1));
for(int i=1;i<=m;i++)
{
if(seg.empty()) {printf("-1"); return 0;}
int j=i,pre=0,t;
while(j<=m && a[i].first==a[j].first) j++;
if(a[i].first-lst>1)
{
pii qwq=mp(seg[0].first,n);
vector<pii>().swap(seg);
seg.pb(qwq);
}
vector<pii>().swap(tmp);
for(int k=i;k<j;k++)
{
if(a[k].second==pre+1) {pre++; continue;}
t=lower_bound(seg.begin(),seg.end(),mp(pre+1,0))-seg.begin();
if(t>0 && seg[t-1].second>=pre+1) tmp.pb(mp(pre+1,a[k].second-1));
else if(t<seg.size() && seg[t].first<a[k].second)
tmp.pb(mp(seg[t].first,a[k].second-1));
pre=a[k].second;
}
if(pre<n)
{
t=lower_bound(seg.begin(),seg.end(),mp(pre+1,0))-seg.begin();
if(t>0 && seg[t-1].second>=pre+1) tmp.pb(mp(pre+1,n));
else if(t<seg.size() && seg[t].first<=n) tmp.pb(mp(seg[t].first,n));
}
lst=a[i].first,i=j-1;
seg=tmp;
}
if(seg.empty()) {printf("-1"); return 0;}
if(lst<n) {printf("%d",2*n-2); return 0;}
if(seg[seg.size()-1].second<n) printf("-1");
else printf("%d",2*n-2);
return 0;
}