[Codeforces 1311F] Moving Points //离散化+树状数组

题目链接

题意:给n(<=2e5)个点,每个点一个初始位置xi(各不相同)和速度vi,(-1e8<=xi,vi<=1e8),d(i,j)定义为i点与j点在所有时刻的最小距离(从0开始的任意时刻,可以不为整数)。求1≤i<j≤n d(i,j)

思路:令xi>xj,如下在这里插入图片描述
所以可以按xi从大到小排序使xi>xi+1,把vi离散化。以vi为下标、xi和点的数量为值放入树状数组。枚举点,查询<=v[i]的点 j 的数量txj值的和sumx,贡献为t*x[i]-sumx,累加贡献即可。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<map>
#include<algorithm>
#include<queue>
#include<math.h>
#include<set>
#include<vector>
using namespace std;
typedef long long ll;
const int N=2e5+7;
int n,V[N];
struct node{
	int x,v;
	bool operator<(const node&o)const{
		return x>o.x;
	}
}a[N];
ll c[N],t[N];
int lowbit(int x){return x&(-x);}
void add(int i,ll val1,ll val2){
	while(i<=n){c[i]+=val1;t[i]+=val2;i+=lowbit(i);}
}
ll qc(int i){ll re=0;while(i>0){re+=c[i];i-=lowbit(i);}return re;}
ll qt(int i){ll re=0;while(i>0){re+=t[i];i-=lowbit(i);}return re;}
int main(){
	cin>>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),V[i]=a[i].v;
	sort(a+1,a+1+n);
	sort(V+1,V+1+n);
	int size=unique(V+1,V+1+n)-V-1;
	for(int i=1;i<=n;i++)a[i].v=lower_bound(V+1,V+1+size,a[i].v)-V;
	ll ans=0;
	for(int i=1;i<=n;i++)add(a[i].v,a[i].x,1);
	for(int i=1;i<n;i++){
		add(a[i].v,-a[i].x,-1);
		ll kc=qc(a[i].v),kt=qt(a[i].v);
		ans+=kt*a[i].x-kc;
	}
	cout<<ans;
}

猜你喜欢

转载自blog.csdn.net/qq_45530271/article/details/104494062