区间合并(排序 +分类/离散化+差分数组+trick)

传送门
题意:给定 n n n 个区间 [ l i , r i ] [li,ri] [li,ri],要求合并所有有交集的区间。
注意如果在端点处相交,也算有交集。
输出合并完成后的区间个数。
例如: [ 1 , 3 ] [1,3] [1,3] [ 2 , 6 ] [2,6] [2,6]可以合并为一个区间 [ 1 , 6 ] [1,6] [1,6]
数据范围 n ≤ 1 e 5 , − 1 e 9 ≤ l i ≤ r i ≤ 1 e 9 n\le1e5,-1e9\le li\le ri\le1e9 n1e5,1e9liri1e9
题解:最直接的想法肯定都是按左端点排序来做,刚开始也是计划这样写来着,好奇问下ysl君有啥思路没,ysl君告诉我离散化后差分下然后维护,想了下,这方法够劲,但是有个小问题就是如果最后一个交集是 [ 1 , 4 ] [1,4] [1,4],另一个是 [ 5 , 6 ] [5,6] [5,6],那么最后统计岂不是让两个又合到一起了,最后就快要放弃这个方法的时候,ysl君说如果中间能有个 4.5 4.5 4.5之类的东西就好了,突然灵光一闪,发现如果离散后直接每个坐标乘上 2 2 2,就会让中间的间隔人为拉大了。
代码

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define rush() int T;scanf("%d",&T);while(T--)
#define mm(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
#define pb push_back
#define sc(a) scanf("%d",&a)
#define pf(a) printf("%d\n",a)
#define p_f(a) printf("%d ",a)
#define sc2(a,b) scanf("%d%d",&a,&b)
#define pf2(a,b) printf("%d %d\n",a,b)
#define db double
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const db eps=1e-9;
const int N=1e5+5;
int n,a[N<<2];
pii segs[N];
vector<int>numbers;
int main()
{
    sc(n);
    rep(i,1,n)cin>>segs[i].first>>segs[i].second;
    rep(i,1,n)numbers.push_back(segs[i].first),numbers.push_back(segs[i].second);
    sort(numbers.begin(),numbers.end());
    numbers.erase(unique(numbers.begin(),numbers.end()),numbers.end());
    rep(i,1,n)segs[i].first=lower_bound(numbers.begin(),numbers.end(),segs[i].first)-numbers.begin()+1,segs[i].second=lower_bound(numbers.begin(),numbers.end(),segs[i].second)-numbers.begin()+1;
    rep(i,1,n)segs[i].first*=2,segs[i].second*=2;
    rep(i,1,n)a[segs[i].first]++,a[segs[i].second+1]--;
    rep(i,1,N*2)a[i]+=a[i-1];
    int count=0;
    for(int i=1;i<=N*2;i++){
        if(a[i]){
            count++;
            for(int j=i+1;j<=N;j++)if(!a[j]){i=j;break;}
        }
    }
    cout<<count<<endl;
    return 0;
}

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值