Segment Tree(set+并查集)

As the name of the task implies, you are asked to do some work with segments and trees.

Recall that a tree is a connected undirected graph such that there is exactly one simple path between every pair of its vertices.

You are given nn segments [l1,r1],[l2,r2],…,[ln,rn][l1,r1],[l2,r2],…,[ln,rn], li<rili<ri for every ii. It is guaranteed that all segments’ endpoints are integers, and all endpoints are unique — there is no pair of segments such that they start in the same point, end in the same point or one starts in the same point the other one ends.

Let’s generate a graph with nn vertices from these segments. Vertices vv and uu are connected by an edge if and only if segments [lv,rv][lv,rv] and [lu,ru][lu,ru] intersect and neither of it lies fully inside the other one.

For example, pairs ([1,3],[2,4])([1,3],[2,4]) and ([5,10],[3,7])([5,10],[3,7]) will induce the edges but pairs ([1,2],[3,4])([1,2],[3,4]) and ([5,7],[3,10])([5,7],[3,10]) will not.

Determine if the resulting graph is a tree or not.

Input
The first line contains a single integer nn (1≤n≤5⋅1051≤n≤5⋅105) — the number of segments.

The ii-th of the next nn lines contain the description of the ii-th segment — two integers lili and riri (1≤li<ri≤2n1≤li<ri≤2n).

It is guaranteed that all segments borders are pairwise distinct.

Output
Print “YES” if the resulting graph is a tree and “NO” otherwise.

Examples
Input
6
9 12
2 11
1 3
6 10
5 7
4 8
Output
YES
Input
5
1 3
2 4
5 9
6 8
7 10
Output
NO
Input
5
5 8
3 6
2 9
7 10
1 4
Output
NO
Note
The graph corresponding to the first example:
在这里插入图片描述

The graph corresponding to the second example:
在这里插入图片描述

The graph corresponding to the third example:
在这里插入图片描述
思路:
脑子抽了一开始用的主席树,过了72个样例之后被卡住了。主要是有一种情况是不能判断出来的,那就是有环的,而且总共的边数=n-1这样的情况。
先按照左端点排序,对于后面的区间,左端点一定大于上面的,我们只需要找到当前的左端点<之前的右端点的点,然后判断右端点是否大于当前右端点就好了。这个操作利用set来实现。除此之外,我们还应该利用并查集判断环。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxx=5e5+100;
struct node{
	int l,r;
	bool operator<(const node &a)const{
		return l<a.l;
	}
}p[maxx];
int f[maxx];
map<int,int> mp;
set<int> s;
int n;

inline int getf(int u)
{
	if(u==f[u]) return f[u];
	else return f[u]=getf(f[u]);
}
inline int merge(int u,int v)
{
	int t1=getf(u);
	int t2=getf(v);
	if(t1==t2) return 1;
	f[t1]=t2;
	return 0;
}
int main()
{
	scanf("%d",&n);
	mp.clear();
	s.clear();
	for(int i=1;i<=n;i++) scanf("%d%d",&p[i].l,&p[i].r),f[i]=i;
	sort(p+1,p+1+n);
	int cnt=0;
	for(int i=1;i<=n;i++) mp[p[i].r]=++cnt;
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		set<int> ::iterator it=s.lower_bound(p[i].l);
		while(it!=s.end()&&*it<p[i].r)
		{
			if(merge(mp[*it],i))
			{
				cout<<"NO"<<endl;
				return 0;
			}
			it++; 
			ans++;
		}
		s.insert(p[i].r);
	}
	if(ans!=n-1) cout<<"NO"<<endl;
	else cout<<"YES"<<endl;
	return 0;
}

努力加油a啊,(o)/~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starlet_kiss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值