CF1284D New Year and Conference(二分+线段树)

这道题抽象出来的问题是,对于每一对点,如果他们的a区间不相交,那么他们的b区间一定相交,反之亦然。

这启发我们可以枚举每个点的a区间,查找是否b区间相交。

快速找到与每个点的a区间相交的办法就是按右端点排序后,在i之前的右端点大于i的左端点的这段区间,我们不必关注i之后的点,因为这些对会在后面的时候被计算到。

之后我们在线段树上查询这段区间即可。我们知道如果区间不相交,那么最小的右端点会小于i的左端点或者最大的左端点大于i的右端点。因此我们维护区间最大最小值即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pll;
const int N=2e6+10;
const int M=2e6+10;
const int inf=0x3f3f3f3f;
struct Q{
    ll a,b,c,d;
}s[N];
vector<int> num;
int n;
struct node{
    int l,r;
    ll mi;
    ll mx;
}tr[N<<1];
bool cmp(Q a,Q b){
    if(a.b==b.b)
        return a.a<b.a;
    return a.b<b.b;
}
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,s[l].d,s[l].c};
    }
    else{
        tr[u]={l,r};
        int mid=l+r>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
        pushup(u);
    }
}
ll query_max(int u,int l,int r){
    if(tr[u].l>=l&&tr[u].r<=r){
        return tr[u].mx;
    }
    int mid=tr[u].l+tr[u].r>>1;
    ll ans=0;
    if(l<=mid)
        ans=query_max(u<<1,l,r);
    if(r>mid)
        ans=max(ans,query_max(u<<1|1,l,r));
    return ans;
}
ll query_min(int u,int l,int r){
    if(tr[u].l>=l&&tr[u].r<=r){
        return tr[u].mi;
    }
    int mid=tr[u].l+tr[u].r>>1;
    ll ans=1e9;
    if(l<=mid)
        ans=query_min(u<<1,l,r);
    if(r>mid)
        ans=min(ans,query_min(u<<1|1,l,r));
    return ans;
}
int solve(){
    sort(s+1,s+1+n,cmp);
    int i;
    num.clear();
    for(i=1;i<=n;i++){
        num.push_back(s[i].b);
    }
    build(1,1,n);
    for(i=1;i<=n;i++){
        if(i==1)
            continue;
        int pos=lower_bound(num.begin(),num.end(),s[i].a)-num.begin()+1;
        if(pos>=i)
            continue;
        int mi=query_min(1,pos,i-1);
        int mx=query_max(1,pos,i-1);
        if(mi<s[i].c||mx>s[i].d)
            return false;
    }
    return true;
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n;
    int i;
    for(i=1;i<=n;i++){
        cin>>s[i].a>>s[i].b>>s[i].c>>s[i].d;
    }
    int ok=1;
    ok&=solve();
    for(i=1;i<=n;i++){
        swap(s[i].a,s[i].c);
        swap(s[i].b,s[i].d);
    }
    ok&=solve();
    if(ok){
        cout<<"YES"<<endl;
    }
    else{
        cout<<"NO"<<endl;
    }
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/13638896.html