Moving Points简单题解

这篇博客主要介绍了如何使用树状数组和离散化的方法解决一道关于动态计算点之间最小距离总和的问题。题目中,n个点分布在坐标轴上,每个点具有一定的速度,需要求出所有点对之间的最小距离之和。博主通过分析得出,对于每个点,只需考虑其左侧且速度更慢的点,利用树状数组记录这些点的位置和数量,从而高效地计算出答案。文章提供了详细的代码实现,包括离散化、树状数组的更新和查询操作,有助于读者理解和应用这类算法。
摘要由CSDN通过智能技术生成

题目来源:

Problem - F - Codeforces

原题:

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).

题意:有一个x轴,上面分布了n个位置为x1,x2.xn,速度为v1,v2...vn,的点,求点所有i,j(1<=i<j<=n)的最小的距离的总和。

题解思路:以右边为正方向,假设有两个点,一左一右,如果左边的点速度比右边的小,那么他们最小的距离在没运动的时候得到,如果左边的速度快,那么最终的最小距离就是左边的点追上右边的点,距离为0。题目可以理解成对于每个点,求在那个点左边并且速度比该点小的点的距离的和。这时候可以用到离散化和树状数组,将点的速度离散化,因为不需要知道他们速度的具体数值,只需要知道他们的大小关系。一个树状数组用于记录比该点速度小且位置在左边的坐标和,一个树状数组用于记录前一个树状数组里面有多少点,这样该点与其他点的距离和就可以变成比自己小的点数*该点的位置-左边的坐标和。

代码:

#include <iostream>
#include <algorithm>
#include <cmath>
#include<cstring>
#include<queue>
#include<map>
#include<cstdlib>
#include<cstdio>
#include<string>
#define ll long long
using namespace std;
int lowbit(int x)//用于在树状数组进行块的跳跃
{
	return x&(-x);
}
const int maxn=2e5+10;
ll c[maxn][2];//用一个二维数组来存储两个树状数组
int n;
void add(ll x,ll v){//改变树状数组块的值
	for(;x<=n;x+=lowbit(x))
	{
		c[x][0]++;//记录点数
		c[x][1]+=v;//记录坐标和
	}
}
ll getsum(ll x,ll k)//树状数组求前缀和
{
	ll ans=0;
	for(;x;x-=lowbit(x))
	ans+=c[x][k];
	return ans;
}
ll speed[maxn];//用于将速度离散化
struct node{
	ll x,v;
}a[maxn];//用于记录点
bool cmp(node a,node b)//给a数组排序,以坐标x从小到大
{
	return a.x<b.x;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);//关闭同步流
cin>>n;
for(int i=1;i<=n;++i)
cin>>a[i].x;//输入

for(int i=1;i<=n;++i)
{
	cin>>a[i].v;//输入
	speed[i]=a[i].v;//给speed 赋值
} 
sort(a+1,a+n+1,cmp);
sort(speed+1,speed+n+1);//speed从小到大排序
int m=unique(speed+1,speed+n)-speed-1;//用unique去重,返回再减去第一个元素的位置,
                                      //就能得到数组还剩多少个元素
ll ans=0;//记录答案
for(int i=1;i<=n;++i)
{
	ll x=lower_bound(speed+1,speed+n+1,a[i].v)-speed;//用二分查找a[i].v在speed中的位置
//比如a[1].x是最小的,得到在speed中的位置后,a[1].x就可以为从小到大第x开始的前缀和做贡献,
//就算用点速度比a[1].v小,但他的坐标一定比a[i].x大,所以第一次进入循环时,ans只能+0,以1到n遍历
 //的顺序保证了每个点利用树状数组进行计算是其中的组成坐标和的坐标一定比a[i].x小,且肯定速度比
//a[i].v小,a[i].x从小到大依次给树状数组以速度排序的坐标和做贡献
	ans+=a[i].x*getsum(x,0)-getsum(x,1);//计算距离的和
	add(x,a[i].x);//将a[i].x加入以从小到大顺序的第xd开始的前缀和
}
cout<<ans;
	return 0;
} 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值