区间操作

区间操作

区间交集

1、用途

若干区间求交集

2、原理

定义区间\(I:\{x|a\le x\le 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\)有交集的充要条件为\(\begin{cases}l_1\le r_2\\ l_2\le 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|a\le x\le 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、备注

①求并集时需要排序。

例题

Codeforces 1341A Nastya and Rice

Gym 102021D Down the Pyramid

51Nod 3086 线段覆盖加强版

HDU 6860 Fluctuation Limit

posted @ 2020-09-01 17:49  Lecxcy  阅读(316)  评论(0编辑  收藏  举报