Line
### Description
数据范围:\(2<=n<=2*10^5,1<=l_i<=r_i<=10^9\)
Solution
稍微想一下就大概是你确定下来\(a_{i}-a_{i+1}\)的值\(d\),再确定下来开始\(a_0\),那么一条线就确定下来了,然后我们要满足:
\[\begin{aligned}
l_i&<=a_0-i\cdot d<=r_i\\
l_i+i\cdot d&<=a_0<=r_i+i\cdot d\\
\end{aligned}
\]
然后我们建立一个横轴表示\(d\),纵轴表示\(a_0\)的坐标系,那么\(l_i+i\cdot d\)和\(r_i+i\cdot d\)就可以看成半平面,\(l_i+i\cdot d\)取上方的,\(r_i+i\cdot d\)取下方的,然后我们预处理出所有\(r_i+i\cdot d\)交出来的一个“上凸壳”和\(l_i+i\cdot d\)交出来的一个“下凸壳”,中间围出来的部分中的整点数量就是答案(实现上的话。。因为斜率就是\(i\)已经排好序了所以直接求凸壳就好了)
因为是整点,所以我们可以直接算面积就好了,具体就是从左往右扫“上下凸壳”,按照交出来的交点把中间的整个部分分成若干个梯形(两边可能是三角形),然后直接用公式计算面积然后加起来就好了
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
const int N=2e5+10,inf=1e9;
struct Dot{
int x,y;
Dot(int x1=0,int y1=0){x=x1; y=y1;}
friend ll crs(Dot a,Dot b){return 1LL*a.x*b.y-1LL*a.y*b.x;}
friend Dot operator - (Dot a,Dot b){return Dot(a.x-b.x,a.y-b.y);}
friend double inter_pot(Dot a,Dot b){return -(1.0*a.y-b.y)/(1.0*a.x-b.x);}
ll val(ll x0){return 1LL*x*x0+y;}
}a[N*2];
Dot lst[N],rst[N];
int l[N],r[N];
int n,topl,topr;
ll ans;
int cmp(Dot x,Dot y,Dot z){
return crs(y-x,z-x)>0?1:-1;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
scanf("%d",&n);
for (int i=1;i<=n;++i){
scanf("%d%d",l+i,r+i);
a[i]=Dot(i,l[i]);
a[i+n]=Dot(i,r[i]);
}
topl=0; topr=0;
for (int i=1;i<=n;++i){
while (topl>1&&cmp(lst[topl-1],lst[topl],a[i])==1) --topl;
lst[++topl]=a[i];
while (topr>1&&cmp(rst[topr-1],rst[topr],a[i+n])==-1) --topr;
rst[++topr]=a[i+n];
}
int pl=1,pr=topr;
ll edl,edr,st=-inf,ed;
while (pl<=topl&&pr){
edl=pl+1<=topl?floor(inter_pot(lst[pl],lst[pl+1])):inf;
edr=pr-1?floor(inter_pot(rst[pr],rst[pr-1])):inf;
ed=min(edl,edr);
if (lst[pl].x<rst[pr].x)
st=max(st,(ll)ceil(inter_pot(lst[pl],rst[pr])));
else if (lst[pl].x>rst[pr].x)
ed=min(ed,(ll)floor(inter_pot(lst[pl],rst[pr])));
if (st<=ed)
ans+=1LL*(ed-st+1)*((rst[pr].val(st)-lst[pl].val(st)+1)+(rst[pr].val(ed)-lst[pl].val(ed)+1))/2;
if (min(edl,edr)==edl) ++pl;
else --pr;
st=min(edl,edr)+1;
}
printf("%lld\n",ans);
}