传送门
题意:给定
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
n≤1e5,−1e9≤li≤ri≤1e9
题解:最直接的想法肯定都是按左端点排序来做,刚开始也是计划这样写来着,好奇问下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;
}