D. 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 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();
}

发布了309 篇原创文章 · 获赞 6 · 访问量 5254

猜你喜欢

转载自blog.csdn.net/qq_43690454/article/details/104081553
今日推荐