题意
给出n个区间,每个区间给出左端点(l)和右端点(r),判断有多少区间成对相交。
分析
如果我们直接暴力查找每个区间是否和别的区间相交,那么时间复杂度就是O(\(n^2\)),肯定是过不了的。
- 考虑如何优化,通过题意,可以发现优化的关键在于区间相交的判定方式,对于任意两个区间l1,l2,r1,r2(l1<l2),考虑相交的情况就有三种判定方式,那么反过来想,判断不相交的情况就只有一种方式,即l2<r1,否则都会相交。然后就可以发现,判断不相交的方式简单,那么我们对全局就可以考虑假设全部相交再减去不相交的情况。
- 全部相交,由于区间1与区间2相交等同与区间2与区间1相交。那么总相交次数为\(C_n^2\)=n(n-1)/2.
- 不相交的次数的判断,对于任意rj,如果rj<li,那么就前面肯定有一个区间和(n-i+1)个区间不相交。
- 从全局看,其实对于区间来说,每一个右端点必然大于左端点。这也是判断区间不相交的基础。那么对于相交的点来说,每个区间的匹配就不那么重要了,因为在相交的情况下,即使任意两个确定的左端点互换了右端点,对整体的相交并没有影响.由此可以推向全部区间。那么区间匹配不重要了,我们就可以直接排序左端点和右端点的数组。
- 这样我们就可以利用双指针来遍历排序好的左端点,右端点数组。按照不相交的判断条件,从总和中减去就行了。
#include <bits/stdc++.h>
#define debug1(X) std::cout << #X << ": " << X << '\n'
#define debug2(X) std::cout << #X << ": " << X << ' '
using i64 = long long;
void solve()
{
i64 n;
std::cin>>n;
std::vector<int>l(n),r(n);
for(int i=0;i<n;i++){
std::cin>>l[i]>>r[i];
}
std::sort(l.begin(),l.end());
std::sort(r.begin(),r.end());
i64 ans=n*(n-1)/2;
int j=0;
for(int i=0;i<n;i++){
while(j<n&&r[j]<l[i]){
j++;
ans-=((n-i));
}
}
std::cout<<ans<<"\n";
}
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t = 1;
// std::cin >> t;
while (t--)
{
solve();
}
return 0;
}
标签:std,int,相交,端点,ABC355,区间
From: https://www.cnblogs.com/sdlypsck/p/18215162