Every year, Farmer John’s N (1 <= N <= 20,000) cows attend “MooFest”,a social gathering of cows from around the world. MooFest involves a variety of events including haybale stacking, fence jumping, pin the tail on the farmer, and of course, mooing. When the cows all stand in line for a particular event, they moo so loudly that the roar is practically deafening. After participating in this event year after year, some of the cows have in fact lost a bit of their hearing.
Each cow i has an associated “hearing” threshold v(i) (in the range 1…20,000). If a cow moos to cow i, she must use a volume of at least v(i) times the distance between the two cows in order to be heard by cow i. If two cows i and j wish to converse, they must speak at a volume level equal to the distance between them times max(v(i),v(j)).
Suppose each of the N cows is standing in a straight line (each cow at some unique x coordinate in the range 1…20,000), and every pair of cows is carrying on a conversation using the smallest possible volume.
Compute the sum of all the volumes produced by all N(N-1)/2 pairs of mooing cows.
Input
Line 1: A single integer, N
Lines 2…N+1: Two integers: the volume threshold and x coordinate for a cow. Line 2 represents the first cow; line 3 represents the second cow; and so on. No two cows will stand at the same location.
Output
Line 1: A single line with a single integer that is the sum of all the volumes of the conversing cows.
Sample Input
4
3 1
2 5
2 6
4 3
Sample Output
57
题意:有n只牛,这n只牛分布在一行上,每个牛的位置是唯一的,不包含两只牛在同一个地方的情况,每一只牛都有一个threshold v(i) 。n只牛之间要相互通信联系,那么N(N-1)/2次配对,每次配对需要计算一个volume;假设i与j需要联系,那么i与j之间的volume=abs(i的位置-j的位置*max(v(i),v(j));
问配对完N(N-1)/2次,总的volume是多少。
分析:
直接暴力是做不出的,因为n的最大值是2e5,n2的复杂度;
我们暴力的目的就是要去判断相互比较的i与j谁的v值大,那么我们为何不先对v值进行排序呢;
struct node{
int id;
ll val;
bool operator < (const node &a) const{
return val<a.val;
}
}b[N<<2];
for(int i=1;i<=n;i++){
scanf("%lld%d",&b[i].val,&b[i].id);
ub=max(ub,b[i].id);//ub是上界
}
sort(b+1,b+1+n);
第一个步骤处理好了,但是距离怎么处理呢,不比较的话,还是不知道他们的距离差;
我们这样来想,如果能有一种方法可以O(n*logn)的复杂度去做就可以了,关键就在这个O(logn);
我们拿我们处理好的排序完的数据来看看;
排完序之后的情况是下面这个样子
v(i) | 2 | 2 | 3 | 4 |
---|---|---|---|---|
位置 | 5 | 6 | 1 | 3 |
我们拿6这个位置的牛来举例,假设当前只有位置为5和位置为6的牛在坐标轴上,那么我们可以很容易算出,两者之间的距离差是6-5=1* 6-5;
(为啥要写一个1* 6-5呢????)这就是问题的处理关键,我们称1* 6中的1为比6小的坐标的个数。
仔细想想如果我们知道,比i小的坐标个数,那么i与比它小的坐标之间的距离差=i的坐标*i小的坐标个数(num_small) - 比i小的坐标和(dis_small)—>是不是呢???
有人可能问了,知道比它小的距离差之和了,那么大的怎么求?
比i大的距离差 = i之间的所有的坐标和(tot) - 比i小的坐标和(dis_small) - 比i位置大的个数*i的位置;–>是不是呢?
ll tot=0,ans=0;
for(int i=1;i<=n;i++){
ll num_small=Query(b[i].id,num);
Update(b[i].id,num,1);
//计算比当前i这个位置小的所有坐标差值和
ll dis_small=num_small*b[i].id-Query(b[i].id,sum);
Update(b[i].id,sum,b[i].id);
ll dis_big=tot+dis_small-num_small*b[i].id-(i-1-num_small)*b[i].id;
tot+=b[i].id;
ans+=b[i].val*(dis_big+dis_small);
}
这里主要的思路已经搭建好的话,那剩下的就是构建树状数组了,它可以在logn的时间复杂度下查询修改区间
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define inf 0x3f3f3f3f
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define lep(i,l,r) for(int i=l;i>=r;i--)
#define ms(arr) memset(arr,0,sizeof(arr))
//priority_queue ,greater >q;
const int N = 1e5 + 10;
const int mod = 1e9+7;
ll sum[N<<2];//统计比i位置小的所有的位置差之和
ll num[N<<2];//统计比i位置小的所有的位置个数
int ub;
int lowbit(int x){
return x&(-x);
}
ll Query(int x,ll a[]){
ll ans=0;
while(x){
ans+=a[x];
x-=lowbit(x);
}
return ans;
}
void Update(int x,ll a[],ll val){
while(x<=ub){
a[x]+=val;
x+=lowbit(x);
}
}
struct node{
int id;
ll val;
bool operator < (const node &a) const{
return val<a.val;
}
}b[N<<2];
int main()
{
// #ifndef ONLINE_JUDGE
// freopen("in.txt","r",stdin);
// #endif // ONLINE_JUDGE
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld%d",&b[i].val,&b[i].id);
ub=max(ub,b[i].id);
}
sort(b+1,b+1+n);
ll tot=0,ans=0;
for(int i=1;i<=n;i++){
ll num_small=Query(b[i].id,num);
Update(b[i].id,num,1);
ll dis_small=num_small*b[i].id-Query(b[i].id,sum);
Update(b[i].id,sum,b[i].id);
ll dis_big=tot+dis_small-num_small*b[i].id-(i-1-num_small)*b[i].id;
tot+=b[i].id;
ans+=b[i].val*(dis_big+dis_small);
}
printf("%lld\n",ans);
return 0;
}