这道题抽象出来的问题是,对于每一对点,如果他们的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; } }
CF1284D New Year and Conference(二分+线段树)
原文:https://www.cnblogs.com/ctyakwf/p/13638896.html