[差分数组]JZOJ 3187 的士

Description

Bessie为农场上的其他奶牛提供的士服务。奶牛们在一条长为M(1<=M<=1,000,000,000)的栅栏的不同位置上。不幸的是,它们厌倦了它们现在所在的位置而想要去栅栏上其他的位置。Bessie必须把她每一个朋友从它们各自的起始地接上车然后送它们到目的地。但Bessie的车太小了,所以她每次只能运送一只奶牛。奶牛们上车下车是瞬间的事情。

    为了省油钱,Bessie想要使她的驾驶量最小。给出N只奶牛(1<=N<=100,000)每一只的起始地和目的地,计算Bessie最少需要的驾驶量。Bessie意识到她需要偶尔把牛放在某一个地方而不是把它送到目的地才能省油钱。

    Bessie在栅栏最左端(位置0)开始工作,而且必须在最右端(位置M)结束她的工作。
 

Input

第一行输入正整数N,M

    接下来N行,每行包括两个整数s_i,t_i(0<=s_i,t_i<=M),表示第i只奶牛的起始地和目的地。

Output

输出一行,Bessie最少需要的驾驶量。(注意最终结果可能会超出32位整数)
 

Sample Input

2 10 
0 9 
6 5

Sample Output

12
 

Data Constraint

1<=N<=100,000
 

Hint

在长度为10的栅栏上,有两只奶牛需要被运送。第一只想要从位置0(Bessie开始工作的地方)到位置9。第二只想要从位置6到位置5。Bessie要把第一只牛从位置0送到位置6,再把第二只牛接上来送到它的目的地位置5,然后再把第一只牛接送到它的目的地位置9,最后驾驶到栅栏的最后端结束工作。

分析

我们可以发现,对于一个区间[l,r],l左侧想要去到r右侧的有a个,r右侧想要去到l左侧的有b个,那么这个区间将要被经过(r-l+1)*(2*a-1)次或(r-l+1)*(2*b+1)次

为什么是“或”而不是“和”呢?我们发现当a>b时,我们每次把a中的一个运过去时,可以顺便把b的一个带过来,所以只用做(r-l+1)*(2*a-1)次,同理b>a也差不多

 

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int a[2*N],s[N][2];
int cnt;
int n,m;
ll ans,L[2*N],R[2*N];

int main() {
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) {
        scanf("%d%d",&s[i][0],&s[i][1]);
        a[++cnt]=s[i][0],a[++cnt]=s[i][1];
    }
    sort(a+1,a+cnt+1);
    cnt=unique(a+1,a+cnt+1)-(a+1);
    for (int i=1;i<=n;i++) {
        int l=lower_bound(a+1,a+cnt+1,s[i][0])-a,r=lower_bound(a+1,a+cnt+1,s[i][1])-a;
        if (l<r) L[l]++,L[r]--;
        else R[l]++,R[r]--;
    }
    for (int i=1;i<=cnt;i++) L[i]+=L[i-1];
    for (int i=cnt;i>=1;i--) R[i]+=R[i+1];
    ans=m-(a[cnt]-a[1]);
    for (int i=2;i<=cnt;i++) {
        int l=L[i-1],r=R[i];
        if (l>r) ans+=1ll*(2*l-1)*(a[i]-a[i-1]);
        else ans+=1ll*(2*r+1)*(a[i]-a[i-1]);
    }
    printf("%lld",ans);
}
View Code

 

posted @ 2019-04-25 20:01  Vagari  阅读(131)  评论(0编辑  收藏  举报