Line

Description

  數據範圍:\(2<=n<=2*10^5,1<=l_i<=r_i<=10^9\)ios

  

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\)已經排好序了因此直接求凸殼就行了)c++

  由於是整點,因此咱們能夠直接算面積就行了,具體就是從左往右掃「上下凸殼」,按照交出來的交點把中間的整個部分分紅若干個梯形(兩邊多是三角形),而後直接用公式計算面積而後加起來就行了spa

  

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);
}
相關文章
相關標籤/搜索