传送门
题意:给定 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
#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
#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;
}