F. Moving Points
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
There are nn points on a coordinate axis OXOX. The ii-th point is located at the integer point xixi and has a speed vivi. It is guaranteed that no two points occupy the same coordinate. All nn points move with the constant speed, the coordinate of the ii-th point at the moment tt (tt can be non-integer) is calculated as xi+t⋅vixi+t⋅vi.
Consider two points ii and jj. Let d(i,j)d(i,j) be the minimum possible distance between these two points over any possible moments of time (even non-integer). It means that if two points ii and jj coincide at some moment, the value d(i,j)d(i,j) will be 00.
Your task is to calculate the value ∑1≤i<j≤n∑1≤i<j≤n d(i,j)d(i,j) (the sum of minimum distances over all pairs of points).
Input
The first line of the input contains one integer nn (2≤n≤2⋅1052≤n≤2⋅105) — the number of points.
The second line of the input contains nn integers x1,x2,…,xnx1,x2,…,xn (1≤xi≤1081≤xi≤108), where xixi is the initial coordinate of the ii-th point. It is guaranteed that all xixi are distinct.
The third line of the input contains nn integers v1,v2,…,vnv1,v2,…,vn (−108≤vi≤108−108≤vi≤108), where vivi is the speed of the ii-th point.
Output
Print one integer — the value ∑1≤i<j≤n∑1≤i<j≤n d(i,j)d(i,j) (the sum of minimum distances over all pairs of points).
Examples
input
Copy
3
1 3 2
-100 2 3
output
Copy
3
input
Copy
5
2 1 4 3 5
2 2 2 3 4
output
Copy
19
input
Copy
2
2 1
-3 0
output
Copy
0
题意:
x轴上有n个点,点xi的移动速度为vi(沿x轴移动),问每两点之间可以达到的最近距离之和。(不一定是同一时刻)
思路:
对于任意两点 x1 < x2 && v1 <= v2 时这两点无法相遇,对结果贡献 x2 - x1
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int n, m;
ll sum[N], cnt[N], v[N]; //sum[]坐标前缀和,cnt[i]左边比现在坐标小、速度小的点的数量,v[]速度离散化数组
struct node
{
int x, v;
} s[N];
bool cmp(node a, node b)
{
return a.x < b.x;
}
void init()
{
memset(sum, 0, sizeof(sum));
memset(cnt, 0, sizeof(cnt));
}
int lowbit(int x)
{
return (-x) & x;
}
void add(int pos, int x, ll c[])
{
while(pos <= n)
{
c[pos] += x;
pos += lowbit(pos);
}
}
ll query(int pos, ll c[])
{
ll res=0;
while(pos>0)
{
res += c[pos];
pos -= lowbit(pos);
}
return res;
}
int main()
{
while(~scanf("%d", &n))
{
init();
for(int i = 1; i <= n; ++i)
{
scanf("%d", &s[i].x);
}
for(int i = 1; i <= n; ++i)
{
scanf("%d", &s[i].v);
v[i] = (ll)s[i].v;
}
sort(s + 1, s + n + 1, cmp); //对坐标从小到大排序
sort(v + 1, v + n + 1);
int tot = unique(v + 1, v + n + 1) - v - 1; //去重
ll ans = 0;
for(int i = 1; i <= n; ++i) //按坐标从小到大枚举
{
int id = lower_bound(v + 1, v + tot + 1, s[i].v) - v; //比该点速度小的速度有多少个(这个点的速度是第几小)
ans += (ll)query(id, cnt) * s[i].x - query(id, sum); //树状数组求区间和:符合条件的点数 * 该点坐标 - 符合条件的点的坐标和
add(id, s[i].x, sum); //坐标和
add(id, 1, cnt); //点数++
}
cout<<ans<<'\n';
}
return 0;
}