题意:Hyunuk会举行一场会议今年,会议由n门演讲组成,Hyunuk有两个候选场馆a和b,每门演讲在不同的场馆都有不同的时间段,分别是[sa, ea] [sb, eb],对于任意两个演讲,如果存在一对演讲,在a场馆时间段相交,在b场馆时间段不相交,或者在b场馆时间段相交,在a场馆时间段不相交,那么意味着这场会议是场馆敏感的,输出YES,否则输出NO。
分析:我们枚举每门演讲i,然后二分查找出和它相交的演讲(在场馆A),然后再判断这两门相交的演讲在场馆B,是否也相交,如果在B不相交,说明是场馆敏感的,同时,我们还需要在B场馆再做一遍这个操作,因为,我们在A场馆二分出来的是和演讲i相交的演讲,然后再去B场馆判断这两门演讲相不相交,因此,我们还需要再做一遍操作,在场馆B中二分,在A场馆中寻找两对相不相交。$$即在A场地冲突是否一定在B场地冲突的情况和在B场地冲突是否一定在A场地冲突的情况都要判断一遍$$
我们使用stl的lower_bound函数去二分演讲i的相交演讲,返回起点大于等于末尾的演讲,假设返回的位置是pos,pos如果是大于等于i + 1,意味着pos和i之间存在着一个或多个相交区间,这些区间都是相交的,然后我们再去查询这些区间的末端最小值和顶端最大值,即ebmin < sbi || sbmax > ebi,即是否至少存在一个在a中和i相交的区间在b中和i不相交,如果存在,就是敏感的,这个,我们可以采用线段树进行优化,返回给定区间的最小值和最大值。
//代码借鉴一个博主的
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100005;
struct Node
{
int sa;
int ea;
int sb;
int eb;
Node(){}
Node(int _sa, int _ea, int _sb, int _eb):sa(_sa), ea(_ea), sb(_sb), eb(_eb){}
bool operator<(const Node& rhs)const
{
if (sa != rhs.sa)
return sa < rhs.sa;
else
return ea < rhs.ea;
}
}node[N];
//线段树
struct tr
{
//该结点代表的区间
int l;
int r;
//该区间涵盖的演讲的最小值
int mi;
//该区间涵盖的演讲的最大值
int mx;
}tr[N * 4];
void pushup(int u)
{
tr[u].mi = min(tr[u << 1].mi, tr[u << 1 | 1].mi);
tr[u].mx = max(tr[u << 1].mx, tr[u << 1 | 1].mx);
}
void build(int u, int l, int r)
{
//叶节点
if (l == r)
{
tr[u] = { l, r, node[l].eb, node[l].sb };
return;
}
int mid = (l + r) >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
pushup(u);
}
//l,r是结点的范围
int querymin(int u, int l, int r, int al, int ar)
{
if (l == al && r == ar)
{
return tr[u].mi;
}
int mid = (l + r) >> 1;
if (ar <= mid) return querymin(u << 1, l, mid, al, ar);
else if (al > mid) return querymin(u << 1 | 1, mid + 1, r, al, ar);
else return min(querymin(u << 1, l, mid, al, mid), querymin(u << 1 | 1, mid + 1, r, mid + 1, ar));
}
int querymax(int u, int l, int r, int al, int ar)
{
if (l == al && r == ar)
{
return tr[u].mx;
}
int mid = (l + r) >> 1;
if (ar <= mid) return querymax(u << 1, l, mid, al, ar);
else if (al > mid) return querymax(u << 1 | 1, mid + 1, r, al, ar);
else return max(querymax(u << 1, l, mid, al, mid), querymax(u << 1 | 1, mid + 1, r, mid + 1, ar));
}
bool solve(int n)
{
sort(node + 1, node + n + 1);
//建立线段树
build(1, 1, n);
for (int i = 1; i <= n; ++i)
{
//二分查找与该lecture相交的lecture
int pos = lower_bound(node + 1, node + n + 1, Node(node[i].ea, 1e9 + 5, 0, 0)) - (node + 1);
//不相交就继续下一次循环
if (!(i + 1 <= pos))
continue;
if (querymin(1, 1, n, i + 1, pos) < node[i].sb || querymax(1, 1, n, i + 1, pos) > node[i].eb)
return false;
}
return true;
}
int main()
{
//n个lecture
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
scanf("%d%d%d%d", &node[i].sa, &node[i].ea, &node[i].sb, &node[i].eb);
}
int flag = 1;
flag = flag & solve(n);
for (int i = 1; i <= n; ++i)
{
swap(node[i].sa, node[i].sb);
swap(node[i].ea, node[i].eb);
}
flag = flag & solve(n);
if (flag)
puts("YES");
else
puts("NO");
return 0;
}