CodeForces - 1311F Moving Points(线段树+离散化)

题目链接:点击查看

题目大意:给出 x 轴上的 n 个点,每个点都有一个位置和一个速度,每个点会根据速度在 x 轴上移动,现在规定dis( x , y )为点 x 和点 y 在移动过程中的最小距离,我们需要求出\sum_{1<=i<j<=n}dis(i,j)

题目分析:比赛时看到这个题知道是可以切的一道题,但没想到给复杂化了,在推出结论和公式后选择了用不太熟悉的主席树去实现,导致最后时间到了也没有debug出来,赛后补题时发现用线段树就可以维护(许多大神们都用树状数组维护的,但我不太会树状数组,还是用比较万能的线段树吧),因为题目给出的点都是基于 x 轴上的,所以我们不妨先对其坐标排个序,然后有个很显然的结论,那就是假设pos[ i ] < pos[ j ]:

  1. 当speed[ i ]<=speed[ j ]时,dis( i , j )为pos[ j ] - pos[ i ]
  2. 当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;
}
发布了657 篇原创文章 · 获赞 22 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/104509263