【CodeForces 1311F】Moving Points

链接:

洛谷

博客园

题目大意:

一条数轴上有 \(n\) 个动点,每个动点的初始坐标是 \(x_i\),它们每秒会向右移 \(v_i\)。求出所有点对最短距离之和。

正文:

假设我们当前正在处理点对 \((i,j)\)。如果 \(v_i<v_j\)

那么它们的距离会越来越远,所以初始距离则是最短距离。


如果 \(v_i=v_j\)

那么它们的距离不会改变,初始距离还是最短距离。


如果 \(v_i>v_j\)

因为时间不一定是整数,所以它们必然会走到一个点,即距离为 \(0\)

那么现在可以把题目转换成:\(x_i<x_j\)\(v_i\leq v_j\) 的点对距离和。显然是二维偏序。维护两个树状数组 \(A,B\),分别维护的是已经维护了点的数量、已维护点到原点距离之和。那么答案是 \(\sum A\cdot x_i-B\)

代码:

const int N = 2e5 + 10;

ll t[2][N], b[N];
int n, m;
ll ans;

void modify(int x, ll val, ll t[]){for (; x <= N - 10; x += x & -x) t[x] += val;}
ll query (int x, ll t[])
{
	ll ans = 0;
	for (; x; x -= x & -x) ans += t[x];
	return ans;
}

struct node
{
	int x, v;
}a[N];

bool cmp (node a, node b) {return a.x < b.x || (a.x == b.x && a.v < b.v);}

int main ()
{
	scanf ("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf ("%d", &a[i].x);
	for (int i = 1; i <= n; i++)
		scanf ("%d", &a[i].v), b[i] = a[i].v;
	sort (a + 1, a + 1 + n, cmp);
	sort (b + 1, b + 1 + n);
	int k = unique(b + 1, b + 1 + n) - b;
	for (int i = 1; i <= n; i++)
		a[i].v = lower_bound(b + 1, b + 1 + k, a[i].v) - b;
	for (int i = 1; i <= n; i++)
	{
		modify(a[i].v, a[i].x, t[0]);
		modify(a[i].v, 1, t[1]);
		ans += query(a[i].v, t[1]) * a[i].x - query(a[i].v, t[0]);
	}
	printf ("%lld\n", ans);
	
	return 0;
}

posted @ 2021-02-26 08:52  Jayun  阅读(51)  评论(0编辑  收藏  举报