Acwing 区间合并

区间合并

主要思想:给定很多区间。若两个区间有交集,将二者合并成一个区间。
具体做法:

  • 先按照区间的左端点进行排序
  • 然后遍历每个区间,根据不同的情况进行合并,有一下几种情况:
    示意图区间
  • 第一种情况,区间不变;
  • 第二种情况,end更新为区间i的右端点;
  • 以上两种情况,可以归结为end更新为max(end,r);r为区间右端点
  • 第三种情况,将当前维护的区间加入结果,并将维护的区间更新为区间i;

下面给出区间合并的板子:

//区间合并
void merge(vector<PII> &segs){
    vector<PII> res;
    
    sort(segs.begin(),segs.end());//对pair先按左端点进行排序,再按右端点排序
    
    int st = -2e9,ed = -2e9; //负无穷
    for(auto seg : segs){
        if(ed < seg.first){//当前维护区间与下一区间无交集
           if(st != -2e9) res.push_back(seg);
           st = seg.first,ed = seg.second;//后移,更新维护区间
        }
        else ed = max(ed, seg.second);//有交集,取两个区间的右端点最大值
    }
    if(st != -2e9) res.push_back({st,ed});//判断,然后将剩下的区间加入
    segs = res;
}

下面来看具体的题目:

给定 n个区间 [ l r , r i ] [l_r,r_i] [lr,ri],要求合并所有有交集的区间。注意如果在端点处相交,也算有交集。输出合并完成后的区间个数。
例如:[1,3]和 [2,6]可以合并为一个区间 [1,6]。

输入格式:

第一行包含整数 n n n,接下来 n n n 行,每行包含两个整数 l l l r r r

输出格式:

共一行,包含一个整数,表示合并区间完成后的区间个数。

输入样例:

5
1 2
2 4
5 6
7 8
7 9

输出样例:

3

本题思路:

  • 读入区间端点 ( l , r ) , (l,r), (l,r),将其存入segs数组内,再设置一个结果数组res数组。这两个数组类型的vector类型,不过是键值对形式的;
  • 将segs排序,设置左右端点 ( s t , e d ) (st,ed) (st,ed)为第一个维护的区间,初始都为无穷大;
  • 遍历segs种的元素(区间),比较当前区间(维护区间)的ed和另一个区间seg的 l l l之间的关系;若 e d < l ed < l ed<l,说明这两个区间没有交集,则直接将此seg区间(注意不能是初始区间)加入到res中,并将待维护的区间变为seg(即更新区间,后移);若 e d < l ed < l ed<l不成立,有交集,则更新 e d ed ed为最大值(这里因为区间排好序,所以不用将st更新为最小)
  • 最后判断segs是否为空,若不为空,则将最后剩余一个维护的区间加入res中;

实现代码:

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

typedef pair<int,int> PII;
vector<PII> segs;
int n;

void merge(vector<PII> &segs){
    vector<PII> res;
    
    sort(segs.begin(),segs.end());//对pair先按左端点进行排序
    
    int st = -2e9,ed = -2e9; //负无穷
    for(auto seg : segs){
        if(ed < seg.first){//当前维护区间与下一区间无交集
           if(st != -2e9) res.push_back(seg);
           st = seg.first,ed = seg.second;//后移,更新维护区间
        }
        else ed = max(ed, seg.second);//有交集,取两个区间的右端点最大值
    }
    if(st != -2e9) res.push_back({st,ed});//判断,然后将剩下的区间加入
    segs = res;
}


int main(){
    cin >> n;
    while(n--){
        int l,r;
        cin >> l >> r;
        segs.push_back({l,r});
    }
    merge(segs);
    cout << segs.size() << endl;
    
    return 0;
}

以上就是区间合并的一些内容,后续如果有相关的习题再进行补充更新~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值