链接:https://ac.nowcoder.com/acm/contest/5403/A
张经理的公司的办公室长达100000米,从最左端开始每间隔1米都有一个工位(从第1米开始有工位),位于第i米的工位称为i号工位,且这些工位都在一条水平线上。他有n个员工,每个员工分别位于xi号工位上(不同员工可能位于同一个工位)。
现在张经理想把员工聚集在某两个工位上,他有q套方案(每套方案包含两个工位号,两个工位号可能相同),他想知道对于每套方案,所有员工都到达两个工位中的某一个所需走的最短路径之和是多少。
输入描述:
第一行输入两个正整数n, q
第二行输入n个正整数xi,分别代表第i个员工的工位
之后q行每行输入两个整数a,b,代表该套方案要求的两个集合位置
(1<=n,q,xi,a,b<=10^5)
输出描述:
对于每套方案,输出一个整数代表答案,每个答案独占一行
示例1
输入
复制
3 2
1 3 5
1 4
2 1
输出
复制
2
4
预处理/二分
因为给出的查询次数是1e5,所以时间复杂度不能高于log级别,简述一种O(1)查询的做法(没用二分):因为给出的查询次数是1e5,所以时间复杂度不能高于log级别,简述一种O(1)查询的做法(没用二分):
每次查询给出的a和b,为了使得答案尽可能的小每次查询给出的a和b,为了使得答案尽可能的小
那么a左边的员工应该前往a,b右边的员工应该前往b那么a左边的员工应该前往a,b右边的员工应该前往b
a和b中间的员工,根据距离a和b的距离分情况讨论(其实不需要讨论),接着往下看a和b中间的员工,根据距离a和b的距离分情况讨论(其实不需要讨论),接着往下看
直接根据样例解释吧,容易理解:直接根据样例解释吧,容易理解:
员工位置分别是1,3,5员工位置分别是1,3,5
第一次查询a = 1,b = 4,所以位于1位置的前往1,位于5位置的前往4第一次查询a=1,b=4,所以位于1位置的前往1,位于5位置的前往4
位于a和b中间的位置有2,3,如果每个位置都有人,那位于2位置的一定会前往1,位于3位置的一定会前往4位于a和b中间的位置有2,3,如果每个位置都有人,那位于2位置的一定会前往1,位于3位置的一定会前往4
思路就是这么个思路,怎样预处理呢?思路就是这么个思路,怎样预处理呢?
预处理所有小于等于i位置的员工个数cpre[i], 所有小于等于i位置的员工下标之和pre[i]预处理所有小于等于i位置的员工个数cpre[i],所有小于等于i位置的员工下标之和pre[i]
预处理所有大于等于i位置的员工个数cfpre[i],所有大于等于i位置的员工下标之和fpre[i]预处理所有大于等于i位置的员工个数cfpre[i],所有大于等于i位置的员工下标之和fpre[i]
那么a左边的员工们需要移动的距离 = cpre[a]*a - pre[a]那么a左边的员工们需要移动的距离=cpre[a]∗a−pre[a]
那么b右边的员工们需要移动的距离 = fpre[b] - cfpre[b]*b那么b右边的员工们需要移动的距离=fpre[b]−cfpre[b]∗b
接下来a和b之间的员工们:[a+1,a+(b-a)/2]区间的员工都去a,[a+(b-a)/2 + 1,b-1]区间的员工都去b接下来a和b之间的员工们:[a+1,a+(b−a)/2]区间的员工都去a,[a+(b−a)/2+1,b−1]区间的员工都去b
距离还是直接O(1)处理,你可以理解成在[a,b]中间切一刀,左半部分去a,右半部分去b,细节就不再简述距离还是直接O(1)处理,你可以理解成在[a,b]中间切一刀,左半部分去a,右半部分去b,细节就不再简述
代码
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<string>
#include<string.h>
#include<queue>
#include <map>
using namespace std;
typedef long long ll;
const ll maxn=1e5+10;
ll a,b[maxn];
ll low[maxn],clow[maxn];
ll high[maxn],chigh[maxn];
int main()
{
ll n,m,i,j,k;
cin >> n >> m;
memset(b,0,sizeof(b));
for(i=0;i<n;i++)
{
scanf("%lld",&a);
b[a]++;
}
ll sum=0,sum2=0;
for(i=1;i<=100000;i++)
{
if(b[i])
{
sum+=b[i];
sum2+=b[i]*i;
}
low[i]=sum;
clow[i]=sum2;
}
sum=0;
sum2=0;
for(i=100000;i>=1;i--)
{
if(b[i])
{
sum+=b[i];
sum2+=b[i]*i;
}
high[i]=sum;
chigh[i]=sum2;
}
ll x,y;
for(i=0;i<m;i++)
{
sum=0;
cin>> x >> y;
if(x>y)
{
ll t;
t=x;
x=y;
y=t;
}
sum+=low[x]*x-clow[x];
sum+=chigh[y]-high[y]*y;
if(y-x>1)
{
k=y-x;
ll mid=x+k/2;
sum+=clow[mid]-clow[x]-(low[mid]-low[x])*x;
sum+=(low[y-1]-low[mid])*y-(clow[y-1]-clow[mid]);
}
cout << sum << endl;
}
}