张经理的员工
题目链接
2020年西北工业大学“编程之星”程序设计挑战赛(大学生程序设计创新实践基地队员春季选拔赛)
题目描述
张经理的公司的办公室长达100000米,从最左端开始每间隔1米都有一个工位(从第1米开始有工位),位于第 i i i 米的工位称为 i i i 号工位,且这些工位都在一条水平线上。他有 n n n 个员工,每个员工分别位于 x i x_i xi 号工位上(不同员工可能位于同一个工位)。
现在张经理想把员工聚集在某两个工位上,他有 q q q 套方案(每套方案包含两个工位号,两个工位号可能相同),他想知道对于每套方案,所有员工都到达两个工位中的某一个所需走的最短路径之和是多少。
输入描述:
第一行输入两个正整数 n , q n, q n,q
第二行输入 n n n 个正整数 x i x_i xi ,分别代表第 i i i 个员工的工位
之后 q q q 行每行输入两个整数 a , b a,b a,b ,代表该套方案要求的两个集合位置
( 1 < = n , q , x i , a , b < = 1 0 5 ) (1<=n,q,xi,a,b<=10^5) (1<=n,q,xi,a,b<=105)
输出描述:
对于每套方案,输出一个整数代表答案,每个答案独占一行。
示例1
输入
3 2
1 3 5
1 4
2 1
输出
2
4
思路:
聚集到
a
,
b
a,b
a,b 两个位置,分成4部分
- a a a 之前的那部分移动到 a a a 位置( a a a 位置有没有人对计算不影响)
- b b b 之后的那部分移动到 b b b 位置
- m i d = ( a + b ) / 2 mid=(a+b)/2 mid=(a+b)/2 (整除), a a a 到 m i d mid mid 之间的数移动到 a a a 位置
- m i d + 1 mid+1 mid+1 到 b b b 之间的数移动到 a a a 位置
Code:
预处理位置坐标的前缀和
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int n, q, l, r, x, pos[N];
ll cnt[N], sum[N];
int main()
{
ios::sync_with_stdio(false), cin.tie(nullptr);
cin >> n >> q;
for (int i = 1; i <= n; i++)
{
cin >> x;
pos[x]++;
}
for (int i = 1; i <= 100000; i++)
{
cnt[i] = cnt[i - 1] + pos[i] * 1LL;
sum[i] = sum[i - 1] + pos[i] * i * 1LL;
}
while (q--)
{
cin >> l >> r;
if (l > r)
swap(l, r);
int mid = (l + r) >> 1;
ll ans = 0;
ans += l * cnt[l] - sum[l]; // L前
ans += sum[100000] - sum[r - 1] - (cnt[100000] - cnt[r - 1]) * r; // R后
ans += sum[mid] - sum[l] - (cnt[mid] - cnt[l]) * l; // L <- mid
ans += r * (cnt[r - 1] - cnt[mid]) - (sum[r - 1] - sum[mid]); // mid-1 -> R
cout << ans << endl;
}
return 0;
}
树状数组
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int n, q, l, r, a;
ll c[2][N]; // 0-人数 1-坐标和
int lowbit(int x) { return x & -x; }
void add(int k, int x, int val)
{
while (x <= n)
{
c[k][x] += val;
x += lowbit(x);
}
}
ll query(int k, int x)
{
ll res = 0;
while (x >= 1)
{
res += c[k][x];
x -= lowbit(x);
}
return res;
}
int main()
{
ios::sync_with_stdio(false), cin.tie(nullptr);
cin >> n >> q;
for (int i = 1; i <= n; i++)
{
cin >> a;
add(0, a, 1);
add(1, a, a);
}
while (q--)
{
cin >> l >> r;
if (l > r)
swap(l, r);
int mid = l + r >> 1;
ll ans = 0;
ll cntl = query(0, l);
ll suml = query(1, l);
ans += cntl * l - suml;
ll cnt_mid = query(0, mid);
ll sum_mid = query(1, mid);
ans += (sum_mid - suml) - (cnt_mid - cntl) * l;
ll cntr = query(0, r);
ll sumr = query(1, r);
ans += (cntr - cnt_mid) * r - (sumr - sum_mid);
ll cntall = query(0, 100000);
ll sumall = query(1, 100000);
ans += (sumall - sumr) - r * (cntall - cntr);
cout << ans << endl;
}
return 0;
}