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;
}
posted @ 2021-09-24 15:42  violet_holmes  阅读(40)  评论(0编辑  收藏  举报