Set of Intervals 题解
蓝蓝题,非常小清新(?)的分类讨论。
首先如果
我们先解决这样一个问题:给定左端点所在的区间
若
若
若
假设
先计算左端点在
再计算左端点在
最后计算两端点都在
显而易见,如果
因此此时的答案为
然后考虑区间包含的情况。若
然后考虑
假设两个区间分别为
假设右端点最大值
否则,首先发现,如果
- 左端点在
[l_{\min},l') 、右端点在[L,l') 的所有区间。构造方法:任意选取一个区间和[l_{\min},R] 合并,并第二次和[L,r_{\max}] 合并。 - 左端点在
(r',R] 、右端点在(r',r_{\max}] 的所有区间。构造方法同理。
最后还要加上左端点在
若
否则(
至此,我们严谨而完整地讨论了整道题目最终答案的每一种情况。
#include <bits/stdc++.h>
using namespace std;
constexpr int maxn=1e6+6;
typedef long long ll;
int t,n,m;
ll calc_noinside(int l1,int r1,int l2,int r2) // left bound in [l1,r1] and right bound in [l2,r2], no inside
{
if(l1>r1 || l2>r2) return 0;
if(r1<l2) return 1ll*(r1-l1+1)*(r2-l2+1);
int R=min(r1,r2),L=max(l1,l2);
if(l1>R || L>r2) return 0;
return 1ll*(L-l1)*(r2-L+1)+1ll*(R-L+1)*(2*r2-L-R)/2ll;
}
int pl[maxn],pr[maxn];
ll calc_inside(int l1,int r1,int l2,int r2) // inside
{
// [l2,r2] is inside [l1,r1]
return calc_noinside(l1,r1,l2,r2)+calc_noinside(l2,r2,l1,r1)-calc_noinside(l2,r2,l2,r2);
}
ll calc(int l1,int r1,int l2,int r2)
{
if(l1>l2) swap(l1,l2),swap(r1,r2);
if(l1==l2 && r1>r2) swap(r1,r2);
if(r1>=r2) return calc_inside(l1,r1,l2,r2);
else return calc_noinside(l1,r1,l2,r2);
}
ll getans()
{
cin>>n;
int posminl=-1,posmaxr=-1,minl,maxr;
for(int i=1;i<=n;++i)
{
cin>>pl[i]>>pr[i];
if(posminl==-1 || pl[posminl]>pl[i]) posminl=i;
if(posmaxr==-1 || pr[posmaxr]<pr[i]) posmaxr=i;
}
minl=pl[posminl];
maxr=pr[posmaxr];
if(n==1) return 1;
if(n==2) return calc(pl[1],pr[1],pl[2],pr[2]);
int l2=2e9,r2=-2e9;
for(int i=1;i<=n;++i)
{
if(posminl==i || posmaxr==i) continue;
l2=min(l2,pl[i]);
r2=max(r2,pr[i]);
}
ll ans=calc(minl,maxr,l2,r2);
if(posminl==posmaxr) return ans;
ans+=calc(minl,l2-1,pl[posmaxr],l2-1);
ans+=calc(r2+1,pr[posminl],r2+1,maxr);
if(n>=4 || pr[posminl]>=l2-1 || pl[posmaxr]<=r2+1)
ans+=calc(minl,l2-1,r2+1,maxr);
else
{
ans+=calc(minl,l2-1,pl[posmaxr],maxr);
ans+=calc(minl,pr[posminl],r2+1,maxr);
ans-=calc(minl,pr[posminl],pl[posmaxr],maxr);
}
return ans;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>t;
while(t--) cout<<getans()<<endl;
cout.flush(); return 0;
}