【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_ileq v_j) 的点对距离和。显然是二维偏序。维护两个树状数组 (A,B),分别维护的是已经维护了点的数量、已维护点到原点距离之和。那么答案是 (sum Acdot 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
", ans);
	
	return 0;
}

原文地址:https://www.cnblogs.com/GJY-JURUO/p/14450368.html