题意:
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;
}