解析:
思维题
我们先了解该怎么计算答案
举个例子
3 2
1 3 5
1 4
2 1
我们把空缺的位置写上0
num:表示前i个数中有几个数出现过
sum:表示前缀和
数组: 1 0 3 0 5
num: 1 1 2 2 3
sum: 1 1 4 4 9
我们来讲第一个询问的右端点是怎么计算答案的
处于右端点的数肯定是到r最近。那现在我们把r看成0,那么右端点右边的所有点到r的距离之和就是 sum[x]-sum[r] (x>=r)
再把r变成原来的数,是不是处于右端点右边的数,每个都要再减去r,因为之前算的总和都是r变成0的,现在r变成原来的数,所以要减去
那么位于右端点右边的个数就是 num[x]-num[r] (x>=r)
又因为每个都要减去r 就是 (num[x]-num[r]) * r
那么右端点这部分的答案就是 (sum[x]-sum[r])-(num[x]-num[r]) * r*
好了现在开始分类讨论
对于往左边走的,我已经介绍过了该怎么计算答案。
对于往右边的,只是反过来退一下,同上
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
int n,q,x,l,r;
ll num[N],sum[N];
int main()
{
scanf("%d %d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
num[x]+=1;
sum[x]+=x;
}
for(int i=1;i<=100000;i++) num[i]+=num[i-1],sum[i]+=sum[i-1];
while(q--)
{
scanf("%d %d",&l,&r);
if(l>r) swap(l,r);
int mid=l+r>>1;
ll ans=num[l]*l-sum[l];
// cout<<num[l]*l-sum[l]<<endl;
ans+=(sum[mid]-sum[l])-(num[mid]-num[l])*l;
//cout<<(sum[mid]-sum[l])-(num[mid]-num[l])*l<<endl;
ans+=(num[r]-num[mid])*r-(sum[r]-sum[mid]);
// cout<<(num[r]-num[mid])*r-(sum[r]-sum[mid])<<endl;
ans+=(sum[100000]-sum[r])-(num[100000]-num[r])*r;
// cout<<(sum[100000]-sum[r-1])-(num[100000]-num[r])*r<<endl;
printf("%lld\n",ans);
}
}