D. Segment Tree------思维(难)+排序+set/好

150 篇文章 0 订阅
18 篇文章 0 订阅

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 n segments [l1,r1],[l2,r2],…,[ln,rn], li<ri for every i. 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 n vertices from these segments. Vertices v and u are connected by an edge if and only if segments [lv,rv] and [lu,ru] intersect and neither of it lies fully inside the other one.

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

Determine if the resulting graph is a tree or not.

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

The i-th of the next n lines contain the description of the i-th segment — two integers li and ri (1≤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
inputCopy

6
9 12
2 11
1 3
6 10
5 7
4 8
outputCopy
YES
inputCopy
5
1 3
2 4
5 9
6 8
7 10
outputCopy
NO
inputCopy
5
5 8
3 6
2 9
7 10
1 4
outputCopy
NO
Note
The graph corresponding to the first example:

在这里插入图片描述

The graph corresponding to the second example:

在这里插入图片描述

The graph corresponding to the third example:

在这里插入图片描述

题意:给你 n个线段[li,ri],每个线段的端点不一样。如果有两个线段相交且不包含,我们就对他们建边。例如[l1,r1],[l2,r2]线段相交那么 1和2建边。题目问你是否能建成一棵树,且不存在环。

解析:暴力O(n^2)不可取。需要O(nlogn)的算法。
对所有区间按左端点从大到小排序。我们用一个vector二元组存放当前的左端点为i,右端点为-i,然后再给vector排序。假设当前为i,那么i之前的端点一定与之相交,一棵树最多有n-1条边,并且我们需要用到并查集来维护
用set保存左端点的信息,每次遇到-i的情况,那么前面的线段一定与之相交,然后我们建边,用并查集维护连通分量。然后删除该线段

说的有可能不太好
这边有视频讲解会更好
https://www.bilibili.com/video/av80058531?p=4



#include<bits/stdc++.h>
using namespace std;
const int N=1e6+100;
pair<int,int> a[N];
int fa[N];
int n;
vector<pair<int,int> > p;
int find(int x)
{
	if(x!=fa[x]) return fa[x]=find(fa[x]);
	return fa[x];
}
void slove()
{
	cin>>n;
	for(int i=1;i<=n;i++) 
	{
		fa[i]=i;
		cin>>a[i].first>>a[i].second;
		p.push_back(make_pair(a[i].first,i));
		p.push_back(make_pair(a[i].second,-i));
	}
	sort(p.begin(),p.end()); //这边排序后,遇到-i的情况,那么之前的线段一定与之相交
	int cnt=0;
	set<pair<int,int> > s;
	for(int i=0;i<p.size();i++)
	{
		if(p[i].second>0)
		{
			s.insert(make_pair(-p[i].first,p[i].second)); //加个负号,这边从大到小排序
		}
		else
		{
			for(auto x:s)
			{
				int id=-p[i].second;
				if(a[id].first==-x.first) break;//如果遇到了自己就break
				if(cnt==n-1) //如果之前已经建了n-1条边,这边一定输出NO
				{
					puts("NO");
					return ;
				}
				if(find(id)==find(x.second)) //这边会构成回路
				{
					puts("NO");
					return ;
				}
				fa[find(id)]=fa[find(x.second)];  
				cnt++; 
			}
			s.erase(make_pair(-a[-p[i].second].first,-p[i].second));//删除该线段
		}

	}   
	if(cnt==n-1) puts("YES");
	else puts("NO"); 
}
int main()
{
	slove();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值