CodeForces1284D New Year and Conference——线段树|ST表+二分

题目链接:https://codeforces.com/contest/1284/problem/D

题目大意:

有n场表演,有两个场地,如果在a场地表演则需要占用[sai,eai]这段时间,在b场地表演则需要占用 [sbi,ebi] 这段时间。如果两个表演,占用了同一个时间点,则认为这两个表演是冲突的。但因为每个表演在a场地和b场地的时间段不同,有表演可能在一个场地冲突而在另一个不冲突。所以所有表演中任取两个表演是否都满足都冲突或者都不冲突,。

Input

3
1 3 2 4
4 5 6 7
3 4 5 5
Output

No

题解:

很好很巧妙的一道题,需要用到线段树|ST表维护最大值+二分。

大致思路:我们可以先枚举在a场地的表演,按照sa和ea升序排序,然后二分求出和a场地冲突的所有表演场次,然后再用线段树维护这些冲突的表演的sb的区间最小值和eb的区间最大值。

为什么要维护这个呢?因为基于这样一个事实,对于两个表演[s1,e1]和[x,y],如果两个表演不冲突那么需要满足s1>y||e1<x。而对于多个表演[s1,e1],[s2,e2].......都与[x,y]冲突,则不存在si>y||ei<x,因此如果max(s1....si)>y||min(e1...ei)<x,则存在表演与[x,y]不冲突。

这样我们可以首先线段树维护sb的所有区间最大值和eb的所有区间最小值,然后二分求出与a场地冲突的表演场次的区间,查询这个区间内的sb的最大值以及eb的最小值,判断是否符合条件就行了。

这里二分有一个很重要的技巧,如果两个表演冲突的话,那么需要满足max(s1,s2)<=min(e1,e2)

对于一个表演[s1,e1],我们二分找到[e1,INF]的位置pos,因为max(s1,e1)<=min(e1,INF)   -> e1<=e1,而对于[i+1,pos]的a表演都和当前位置的表演冲突,因为pos位置前面的表演要么sa小要么ea小。

这里只考虑了在a场地表演冲突,b场地表演不冲突的情况,没有考虑b场地表演冲突,a场地表演不冲突的情况,这里我们只需要把sa和sb,以及ea和eb交换一下。

很巧妙的一道题。

代码实现:

#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#define PI atan(1.0)*4
#define E 2.718281828
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define debug printf("ac\n");
using namespace std;
inline int read()
{
    int a=0,b=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-')
            b=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        a=(a<<3)+(a<<1)+c-'0';
        c=getchar();
    }
    return a*b;
}
const int INF = 0x3f3f3f3f;
const int N = 1e5+7;
struct node{
    int sa,ea,sb,eb;
    node(){};
    node(int sa,int ea,int sb,int eb):sa(sa),ea(ea),sb(sb),eb(eb){};
    bool operator<(const node& others){
        return sa==others.sa?ea<others.ea:sa<others.sa;
    }
}p[N];
int MAX[N<<2],MIN[N<<2];
void pushup(int rt){
    MAX[rt]=max(MAX[rt<<1],MAX[rt<<1|1]);
    MIN[rt]=min(MIN[rt<<1],MIN[rt<<1|1]);
}
void build(int l,int r,int rt){
    if(l==r){
        MAX[rt]=p[l].sb;
        MIN[rt]=p[l].eb;
        return ;
    } 
    int m=l+r>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
int queryMIN(int l,int r,int rt,int ql,int qr){
    if(ql<=l&&r<=qr) return MIN[rt];
    int m=l+r>>1;
    if(qr<=m) return queryMIN(lson,ql,qr);
    else if(ql>=m) return queryMIN(rson,ql,qr);
    else return min(queryMIN(lson,ql,m),queryMIN(rson,m+1,qr));
}
int queryMAX(int l,int r,int rt,int ql,int qr){
    if(ql<=l&&r<=qr) return MAX[rt];
    int m=l+r>>1;
    if(qr<=m) return queryMAX(lson,ql,qr);
    else if(ql>=m) return queryMAX(rson,ql,qr);
    else return max(queryMAX(lson,ql,m),queryMAX(rson,m+1,qr));
}
bool solve(int n){
    sort(p+1,p+1+n);
    build(1,n,1);
    rp(i,1,n){
        int pos=lower_bound(p+1,p+1+n,node(p[i].ea,INF,0,0))-p-1;
        if(i+1>pos) continue;
        if(queryMIN(1,n,1,i+1,pos)<p[i].sb||queryMAX(1,n,1,i+1,pos)>p[i].eb) return false;
    }
    return true;
}
int main(){
    int n=read();
    rp(i,1,n) p[i].sa=read(),p[i].ea=read(),p[i].sb=read(),p[i].eb=read();
    int cnt=0;
    if(solve(n)) cnt++;
    rp(i,1,n) swap(p[i].sa,p[i].sb),swap(p[i].ea,p[i].eb);
    if(solve(n)) cnt++;
    if(cnt==2) cout<<"Yes"<<endl;
    else cout<<"No"<<endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值