數據範圍:\(2<=n<=2*10^5,1<=l_i<=r_i<=10^9\)ios
稍微想一下就大概是你肯定下來\(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\)已經排好序了因此直接求凸殼就行了)c++
由於是整點,因此咱們能夠直接算面積就行了,具體就是從左往右掃「上下凸殼」,按照交出來的交點把中間的整個部分分紅若干個梯形(兩邊多是三角形),而後直接用公式計算面積而後加起來就行了spa
#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); }