【区间合并】洛谷 P1496 火烧赤壁

P1496 火烧赤壁

文章目录

  • 题目背景
    • 题目描述
    • 输入格式:
    • 输出格式:
    • 数据范围
    • 输入样例
    • 输出样例
  • 方法:区间合并
    • 解题思路
    • 代码
    • 复杂度分析:

题目背景

曹操平定北方以后,公元 208 年,率领大军南下,进攻刘表。他的人马还没有到荆州,刘表已经病死。他的儿子刘琮听到曹军声势浩大,吓破了胆,先派人求降了。

孙权任命周瑜为都督,拨给他三万水军,叫他同刘备协力抵抗曹操。

隆冬的十一月,天气突然回暖,刮起了东南风。

没想到东吴船队离开北岸大约二里距离,前面十条大船突然同时起火。火借风势,风助火威。十条火船,好比十条火龙一样,闯进曹军水寨。那里的船舰,都挤在一起,又躲不开,很快地都烧起来。一眨眼工夫,已经烧成一片火海。

曹操气急败坏的把你找来,要你钻入火海把连环线上着火的船只的长度统计出来!

题目描述

给定每个起火部分的起点和终点,请你求出燃烧位置的长度之和。

输入格式:

第一行一个整数,表示起火的信息条数 n。
接下来 n 行,每行两个整数 a, b,表示一个着火位置的起点和终点(注意:左闭右开)。

输出格式:

输出一行一个整数表示答案。

数据范围

  • 1 ≤ n ≤ 2 × 1 0 4 1≤n≤2\times10^4 1n2×104
  • − 2 31 ≤ a ≤ b < 2 31 -2^{31} \leq a \leq b \lt 2^{31} 231ab<231

输入样例

3
-1 1
5 11
2 9

输出样例

11

方法:区间合并

解题思路

  • 按区间的左端点进行从小到大的排序
  • 我们把维护区间的左端点记为指针 st,右端点记为指针 ed
    每次搜索一个新的区间,它与维护区间之间有 3 种情况:
    【区间合并】洛谷 P1496 火烧赤壁_第1张图片
    • 新区间是维护区间的子区间
    • 新区间与维护区间有相交部分
    • 新区间与维护区间没有相交部分

依据新区间和维护区间是否有相交的部分,可以将上述 3 种情况视为 2 种情形。
如果新区间的左端点 > 维护区间的右端点,则两个区间没有相交部分,则将维护区间的左右端点保存起来;
如果新区间的左端点 <= 维护区间的右端点,则两个区间有相交部分,则更新维护区间的右端点,取两个区间右端点的最大值。

Tips

  • sort 在 c++ 中,会优先对左端点进行从小到大的排序,再对右端点进行从小到大的排序。
  • 将 vector 容器作为函数参数,使用引用传递的方式,在形式参数前加上 &,函数内部形参发生变化时,这种改变可以直接传递给被调用的实参。
  • 注意 st != -2e9,把 -2e9 换成再小一点的数就会报错,有哪位大佬懂得可以告诉我吗?

代码

#include 
#include 
#include 

using namespace std;

typedef pair<long,long> PII;

vector<PII> segs;
int n;

void merge(vector<PII> &segs) {
    vector<PII> res;
    sort(segs.begin(), segs.end());
    long st = -2e9, ed = -2e9;
    for(auto seg : segs) {
        if(ed < seg.first) {
            if(st != -2e9) 
                res.push_back({st, ed});
            st = seg.first, ed = seg.second;
        }
        else    ed = max(seg.second, ed);
    }
    if(st != -2e9)    res.push_back({st, ed});
    segs = res;
}

int main() {
    cin >> n;
    while(n--) {
        long l, r;
        cin >> l >> r;
        segs.push_back({l, r});
    }
    merge(segs);
    int sum = 0;
    for(auto seg : segs) {
    	sum += seg.second - seg.first;
    }
    cout << sum;
    return 0;
}

复杂度分析:

  • 时间复杂度: O ( n × l o g 2 n ) O(n\times log_2n) O(n×log2n)
  • 空间复杂度: O ( n ) O(n) O(n)

你可能感兴趣的:(#,区间合并,算法之路,c++)