题目描述:在宽109高109的棋盘上,从下到上编号为1到10^9,从左到右编号为1到10^9。因此,对于棋盘的每个单元格,可以指定坐标(x,y),其中x是列号,y是行号。在棋盘的左下角(1,1)处有一个棋子,在棋盘上有很多的阻隔墙(垂直的和水平的),求棋子到达最后一行至少需要翻过几道墙。
输入:第一行包含两个整数n和m(0≤n,m≤10^5)垂直和水平阻隔墙的数量。
以下n行包含一个整数x(1≤x < 109),表示在x和x+1列之间有一道垂直阻隔墙。
以下m行包含三个整数x1,x2和y(1 ≤x1,x2≤10^9,1≤y < 10^9),表示在第y行与第y+1行之间有一道从第x1列到第x2列的水平阻隔墙。
输出:棋子到达最后一行至少需要翻过几道墙。
解题思路:实际上这道题是要求有多少个封闭的空间,且任意两个封闭空间的都不能共用一条边。如果水平阻隔墙的起始位置不是第一列,那么一定不会组成封闭空间,如果水平阻隔墙的长度等于10^9,那么棋子至少要翻过这道墙,因为任意两道墙都不能有公共边,所以用vis数组标记已经组成了封闭空间的垂直阻隔墙。
AC代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define io ios::sync_with_stdio(0),cin.tie(0)
#define ms(arr) memset(arr,0,sizeof(arr))
#define inf 0x3f3f3f
typedef long long ll;
const int mod=1e9+7;
const int maxn=2e5+7;
int n,m;
int b[maxn];
int vis[maxn];
int main()
{
io;
cin>>n>>m;
for(int i=0; i<n; i++)
cin>>b[i];
sort(b,b+n);
ms(vis);
int ans=0;
for(int i=1; i<=m; i++)
{
int a1,a2,c;
cin>>a1>>a2>>c;
if(a1==1)//水平阻隔墙的起始位置必须是第一列,才有可能组成封闭空间
{
if(a2==1000000000)//水平阻隔墙的长度等于10^9,那么棋子至少要翻过这道墙
{
ans++;
continue;
}
int k=upper_bound(b,b+n,a2)-b-1;//找到第一个不大于水平阻隔墙长度的垂直阻隔墙,并与之组成封闭空间
while(vis[k]==1&&k>=0)//若这道垂直阻隔墙已经与其他水平阻隔墙组成了封闭空间,那么向下寻找,直到找到未被标记的垂直阻隔墙
{
k--;
}
if(k>=0)//如果能够找到这道垂直阻隔墙,那么能够组成封闭空间,需要翻墙
{
ans++;
vis[k]=1;
}
}
}
cout<<ans<<endl;
return 0;
}