POJ1990--MooFest(转化为树状数组)

题意:

n头牛,每头牛有两个值,v和x,两两之间有一个值,设v分别为v1,v2, x为x1,x2,则它们之间的值为abs(x1-x2) * Max(v1,v2), 求所有n*(n-1)/2对牛之间值的总和。

思路:

看了https://blog.csdn.net/bestsort/article/details/80853221,有图真好,一下就清楚了,下面的图也是摘自那里
按照题意,是求:
在这里插入图片描述
将牛按照v值排序,可以改为:
在这里插入图片描述
这样当处理第i头牛的时候,它的 v 值就是当前最大的,剩下需要考虑的就是坐标的距离差了。
假设当前正在处理第 i 头牛,它的v值一定是这1到 i 里最大的,由于是按照v排序,所有v值它的牛可以分成两类,一类是坐标位于它左边,一类是右边。
对于左边的牛,只需求出他们与第 i 头牛的距离之差的和 L。L = ln * Xi - S;
(Xi是第 i 头牛的坐标, ln 是左边所有坐标<Xi的牛的个数,S 是这些牛的坐标之和)
在这里插入图片描述

对于右边的牛,他们与第 i 头牛的距离之差的和为R,R = totdis - S - rn*Xi;rn = i-1-ln
设当前累计的坐标之和为totdis,利用上面求出的左边的坐标之和为S, rn 是右边所有坐标<Xi的牛的个数。
在这里插入图片描述
注意用long long

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5+5;
using namespace std;
LL n, C[2][maxn];

struct Node{
	int v,x;
	bool operator < (const Node& rhs) const{
		return v < rhs.v;
	}
}nodes[maxn];

inline int lowbit(int x){ return x & -x; }
void add(int x, int v, int u){for(int i = x; i < maxn; i+= lowbit(i)) C[u][i]+= v;}
LL sum(int x, int u){
	LL s = 0;
	for(int i = x; i > 0; i-= lowbit(i)) s+= C[u][i];
	return s;
}

int main()
{
    freopen("in.txt","r",stdin);
    LL totdis,ans;
	while(scanf("%d",&n) == 1){
		memset(C, 0, sizeof(C));
		totdis = 0; ans = 0;
		for(int i = 1; i <= n; ++i) scanf("%d%d", &nodes[i].v, &nodes[i].x);
		
		sort(nodes+1, nodes+n+1);
		
		for(int i = 1; i <= n; ++i){
			LL ln = sum(nodes[i].x, 0);		// 左边坐标 < x的个数 
			LL lw = sum(nodes[i].x, 1); 	// 左边坐标 < x的坐标之和
			LL L = ln*nodes[i].x - lw;
			LL rn = i-1 - ln;					// 右边坐标 < x的个数 
			LL R = totdis - lw - rn*nodes[i].x;
			
			ans+= (L+R)*nodes[i].v;
			totdis+= nodes[i].x;			// 总坐标长度
			
			add(nodes[i].x, 1, 0);
			add(nodes[i].x, nodes[i].x, 1);
		}
		printf("%lld\n", ans);
	}
    fclose(stdin);
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值