题目链接:点击查看
题目大意:给出 x 轴上的 n 个点,每个点都有一个位置和一个速度,每个点会根据速度在 x 轴上移动,现在规定dis( x , y )为点 x 和点 y 在移动过程中的最小距离,我们需要求出
题目分析:比赛时看到这个题知道是可以切的一道题,但没想到给复杂化了,在推出结论和公式后选择了用不太熟悉的主席树去实现,导致最后时间到了也没有debug出来,赛后补题时发现用线段树就可以维护(许多大神们都用树状数组维护的,但我不太会树状数组,还是用比较万能的线段树吧),因为题目给出的点都是基于 x 轴上的,所以我们不妨先对其坐标排个序,然后有个很显然的结论,那就是假设pos[ i ] < pos[ j ]:
- 当speed[ i ]<=speed[ j ]时,dis( i , j )为pos[ j ] - pos[ i ]
- 当speed[ i ]>speed[ j ]时,dis( i , j )为 0
这样一来,遍历每个点 i ,对答案有贡献的点无非就是位置在点 i 之前,且速度小于等于speed[ i ]的点,而贡献就是其距离差之和了,可以利用前缀和轻松求出,设cnt为速度小于等于speed[ i ]的点的个数,sum为这cnt个点的坐标之和,那么贡献就是speed[ i ] * cnt - sum了,线段树维护一下就好了,为了方便传参,我自己定义了一个结构体代替了pair
最后需要注意的是,速度的范围有点大,但我们只需要用到速度的相对大小,所以可以对速度离散化一下方便操作,线段树的下标为速度,值为其位置
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=2e5+100;
vector<int>v;//离散化
struct Pair
{
int cnt;
LL sum;
Pair(int cnt,LL sum):cnt(cnt),sum(sum){}
Pair operator+(const Pair& a)
{
return Pair(cnt+a.cnt,sum+a.sum);
}
};
struct Point
{
int pos,speed;
bool operator<(const Point& a)const
{
return pos<a.pos;
}
}a[N];
struct Node
{
int l,r,cnt;
LL sum;
}tree[N<<2];
void pushup(int k)
{
tree[k].cnt=tree[k<<1].cnt+tree[k<<1|1].cnt;
tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}
void build(int k,int l,int r)
{
tree[k].l=l;
tree[k].r=r;
tree[k].cnt=tree[k].sum=0;
if(l==r)
return;
int mid=l+r>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
void update(int k,int pos,int val)
{
if(tree[k].l==tree[k].r)
{
tree[k].cnt++;
tree[k].sum+=val;
return;
}
int mid=tree[k].l+tree[k].r>>1;
if(mid>=pos)
update(k<<1,pos,val);
else
update(k<<1|1,pos,val);
pushup(k);
}
Pair query(int k,int l,int r)
{
if(tree[k].l>r||tree[k].r<l)
return Pair(0,0LL);
if(tree[k].l>=l&&tree[k].r<=r)
return Pair(tree[k].cnt,tree[k].sum);
return query(k<<1,l,r)+query(k<<1|1,l,r);
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i].pos);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].speed);
v.push_back(a[i].speed);
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
for(int i=1;i<=n;i++)
a[i].speed=lower_bound(v.begin(),v.end(),a[i].speed)-v.begin()+1;
sort(a+1,a+1+n);
build(1,1,v.size());
LL ans=0;
for(int i=1;i<=n;i++)
{
Pair temp=query(1,1,a[i].speed);
ans+=1LL*a[i].pos*temp.cnt-temp.sum;
update(1,a[i].speed,a[i].pos);
}
printf("%lld\n",ans);
return 0;
}