Hello 2020 D. New Year and Conference

题目链接

题意:

有 n 个事件,在 A 会议室开会的时间段是 abegin aend, 在 B 会议室开会的时间段是bbegin bend。 现在的要求是在 A 会议室中任意事件相交,那么在 B 会议室中这些事件也要相交, 同理,在 B 会议室中任意事件相交,那么在 A 会议室中这些事件也要相交, 如果满足条件 输出 YES , 否则输出 NO。

思路:

对于所有的事件, 我们按照在 A 会议室中的时间顺序,将开始时间从小到大排序,那么 B 会议室中也要跟着排序,
然后 我们枚举 A 会议室中的每一个事件,由于起始时间是有序的, 所以我们可以找到一个区间,这个区间中的所有事件都与枚举的事件相交。 然后我们用线段树维护 B 会议室中的事件,把每个事件的起始时间和结束事件放到线段树中,找到这个区间中所有事件最小的结束时间,最大的开始时间, 看这两个时间和当前枚举事件的时间关系,判断是不是都相交。
如果存在 mx < begin || mn > end 那么就说明有不相交的, 就要输出 NO。

然后我们交换 A B 会议室中的事件内容, 重新做一遍。

反思:

做这道题的时候,完全没有想到要怎么做, 一开始想的是枚举 时间点,看有几个事件是覆盖这个事件点的, 然后去判断 B 会议室。
但是想着想着就不会了, 然后又想着怎么找几个事件他们是相交的,也没有想出来。

最终还是要枚举事件,

#include<bits/stdc++.h>
#define lson  now << 1
#define rson  now << 1 | 1
using namespace std;
const int N = 1e5+100;

void dbg() {cout << endl;}
template<typename T, typename... A> void dbg(T a, A... x) {cout << a << ' '; dbg(x...);}
#define logs(x...) {cout << #x << " -> "; dbg(x);}

int n,m;
struct node{
    int a,b,c,d;
    bool operator < (const node&A) const{
        if (a != A.a) return a < A.a;
        return b < A.b;
    }
}f[N];
int mn[N*4],mx[N*4],ansmn,ansmx;
vector<int>g;
void build(int now, int l, int r){
    if (l + 1 == r){
        mx[now] = f[l-1].c;
        mn[now] = f[l-1].d;
        return;
    }
    int mid = (l + r) >> 1;
    build(lson, l, mid); build(rson, mid, r);
    mx[now] = max(mx[lson], mx[rson]);
    mn[now] = min(mn[lson], mn[rson]);
}
void ask(int now, int l, int r, int a, int b){
    if (a <= l && b >= r - 1){
        ansmx = max(ansmx, mx[now]);
        ansmn = min(ansmn, mn[now]);
        return;
    }
    int mid = (l + r) >> 1;
    if (a < mid) ask(lson, l, mid, a, b);
    if (b >= mid) ask(rson, mid, r, a, b);
}

void solve(){
    sort(f, f + n);
    g.clear();
    for (int i = 0;i < n; ++i)
        g.push_back(f[i].a);
    sort(g.begin(), g.end());
    for (int i = 0; i < n* 4+10; ++i){
        mx[i] = 0; mn[i] = 1e9+10;
    }
    build(1,1,n+1);
    int L , R;
    for (int i = 0; i < n; ++i){
        L = i + 2;  R = upper_bound(g.begin(), g.end(), f[i].b) - g.begin();
        if (L > R) continue;
        ansmx = 0; ansmn = 1e9+100;
        ask(1,1,n+1,L, R);
        if (ansmn < f[i].c || ansmx > f[i].d) {
            // logs(i, ansmn, ansmx, f[i].a, f[i].b);
            puts("NO");
            exit(0);
        }
    }
}
int main(){
    scanf("%d",&n);
    for (int i = 0; i < n; ++i)
        scanf("%d%d%d%d",&f[i].a,&f[i].b ,&f[i].c ,&f[i].d);
    solve();
    for (int i = 0; i < n; ++i){
        swap(f[i].a, f[i].c);
        swap(f[i].b, f[i].d);
    }
    solve();
    puts("YES");
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值