题意:
给了n个区间,对于任意两个区间,如果两个区间有交集,那么就对这两个区间连边。(要求区间不能是对方的子集)。问进行连边之后,能不能形成一棵树。
思路:
考虑暴力建边的话,n^2的复杂度显然是不允许的。
考虑一下,形成一棵树,也就是只需要n-1条边,如果>n-1条边,那么就形成了环了,也就不是树了。
所以我们考虑对输入的区间,进行左端点从小到大排序。
用一个set维护前面的区间的右端点和id。
对于当前的区间,我们是按照左端点排序的,也就是当前左端点L2一定大于set中的左端点L1,那么也就是要找到set中的右端点R1大于当前的左端点L2,并且set中的右端点R1小于当前区间的右端点R2,不然当前的区间就是set中那个区间的子集了。用并查集维护联通的区间的个数即可。
如果形成了环,或者边不足n-1 那么就是NO。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int f[N];
int find(int x){
return f[x]==x?f[x]:f[x]=find(f[x]);
}
struct node{
int l,r;
}a[N];
struct E{
int id,r;
friend bool operator<(E a,E b){
return a.r<b.r;
}
};
set<E> s;
int main(){
int n;scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d%d",&a[i].l,&a[i].r),f[i]=i;
sort(a+1,a+n+1,[](node a,node b){
return a.l<b.l;
});
int F;
for(int i=1;i<=n;i++){
auto it=s.lower_bound({i,a[i].l});
while(it!=s.end() && it->r < a[i].r){
int fx=find(it->id),fy=find(i);
if(fx==fy) goto now;
f[fx]=fy;
it++;
}
s.insert({i,a[i].r});
}
F=find(1);
for(int i=1;i<=n;i++){
if(find(i)!=F) goto now;
}
puts("YES");
return 0;
now: puts("NO");
}