区间操作
区间交集
1、用途
若干区间求交集
2、原理
定义区间(I:{x|ale xle b}),以下简记为([a,b])。
注意到两个区间交集的左端点一定是其中某一个区间的左端点,右端点也一定是其中某一个区间的右端点。于是区间(I_1:[l_1,r_1])与(I_2:[l_2,r_2])的交集为([max(l_1,l_2),min(r_1,r_2)])。
由交集的表达式推出(I_1)与(I_2)有交集的充要条件为(egin{cases}l_1le r_2\ l_2le r_1 end{cases})。
3、复杂度
(O(n))
4、模板
struct seg
{
int l, r;
bool operator <(seg others)
{
if (l == others.l) return r < others.r;
else return l < others.l;
}
};
seg intersec(vector <seg> &a) //若无交集,返回值l > r
{
int l = -INF, r = INF;
for (int i = 0; i < n; ++i)
{
l = max(l, a[i].l), r = min(r, a[i].r);
if (l > r) return {l, r};
//有交集时的逻辑
}
return {l, r};
}
5、备注
①求交集时不需要排序。
区间合并
1、用途
若干区间求并集
2、原理
定义区间(I:{x|ale xle b}),以下简记为([a,b])。
首先按区间左端点对所有区间进行排序。
假设之前已经完成合并操作的区间左端点为(l),右端点为(r),目前正在合并第(i)个区间。
由于左端点的有序性,因此(l le l[i])。下面分两种情况讨论。
①:(l[i]le r)。此时第(i)个区间与之前合并完成的区间有交集,意味着之前合并完成的区间有向右拓展的可能。这时只需要(r=max(r,r[i]))即可。
②:(l[i]>r)。此时第(i)个区间与之前合并完成的区间没有交集。而由于区间左端点的有序性,在此之后的所有区间(I_j)均满足(l[j] ge l[i] >r),因此从(i)开始往后的所有区间都和当前已合并完成的区间没有交集。这时将({l,r})加入答案,并把(l)重新赋值成(l[i])、(r)重新赋值成(r[i])、继续向后遍历即可。
3、复杂度
(O(nlogn))
4、模板
struct seg
{
int l, r;
bool operator <(seg others)
{
if (l == others.l) return r < others.r;
else return l < others.l;
}
};
vector <seg> unite(vector <seg> &a)
{
vector <seg> ans;
if (a.empty()) return ans; //小心re
sort(a.begin(), a.end());
int l = a[0].l, r = a[0].r;
for (int i = 1; i < a.size(); ++i)
if (a[i].l <= r) r = max(r, a[i].r);
else ans.push_back({l, r}), l = a[i].l, r = a[i].r;
ans.push_back({l, r});
return ans;
}
5、备注
①求并集时需要排序。