题目是这样的:由于参加MooFest这个会议,使得有些奶牛耳聋了,我们现在就是想要知道要多少的声量使得所有牛两两之间都能听清,题目给出vi与xi分别代表最先听清所需的声量、这头奶牛在坐标上的位移。而题目让我们求得是,所需要的总和,也就是全体max(vi, vj)*abs(xi-xj)之和。
题面(后附上思路):
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
思路:
我们要求所有的值,既然要比较vi与vj的较大值,不妨就按照v的大小,按照升序排列,这样在vi之前的元素,他们要与vi建立联系,肯定是以vi的大小作为基底的。
接下来,我们对其中一个vi作为参考系来进行比较,我们接下来就要考虑的是xi的关系,对于xi,在其之前的元素,有比它大的,也有比它小的(就是不可能有相等的) ,这个时候可以把xi之前的那些{x}集合分成比xi小的以及比xi大的。那些比xi小的{x}可以用树状数组找到其个数a以及总量b,那么小于xi 的集合总大小就是a*xi-b;接下来,考虑大于xi的{x}集合,因为我们现在知道xi,那么就知道它是第i位,在此之前有(i-1)个元素,我们可以先弄一个前缀和,求得在此之前的到此位且不包含此位的元素的大小总和len[i],然后计算len[i]-b-(i-1-a)*xi即可求得大于xi的范围的总和。
完整代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
using namespace std;
typedef long long ll;
const int maxN=20005;
struct node
{
ll v,x;
node(ll a=0, int b=0) {v=a; x=b;}
}mp[maxN];
int N;
ll bita[maxN]; //用以记录小于x的点的数目,那么,我们接下来只需要知道小于x点的点的距离和即可
ll bitlen[maxN]; //记录下小于x的点的距离和,然后找到x之前元素的全体的前缀和即可求解关于i点的vi需求
ll qzsum[maxN]; //前缀和
bool cmp(node e1, node e2)
{
return e1.v==e2.v?(e1.x<e2.x):(e1.v<e2.v);
}
void update_a(ll i, ll x) //点数量的更新方式是把(xj, 1)放进去
{
while(i<=maxN)
{
bita[i]+=x;
i+=lowbit(i);
}
}
void update_len(ll i, ll x) //长度的更新方式是把(xj, xj)放进去,然后求的时候是求Query_len(xi)
{
while(i<=maxN)
{
bitlen[i]+=x;
i+=lowbit(i);
}
}
ll Query_a(ll i)
{
ll res=0;
while(i)
{
res+=bita[i];
i-=lowbit(i);
}
return res;
}
ll Query_len(ll i)
{
ll res=0;
while(i)
{
res+=bitlen[i];
i-=lowbit(i);
}
return res;
}
int main()
{
while(scanf("%d",&N)!=EOF)
{
ll ans=0; //这是最后所要求的答案
memset(mp, 0, sizeof(mp));
memset(bita, 0, sizeof(bita)); //计数的
memset(bitlen, 0, sizeof(bitlen)); //记长的
memset(qzsum, 0, sizeof(qzsum)); //记总长的
for(int i=1; i<=N; i++)
{
scanf("%lld%lld",&mp[i].v,&mp[i].x);
}
sort(mp+1, mp+1+N, cmp);
for(int i=1; i<=N; i++) qzsum[i]=qzsum[i-1]+mp[i-1].x; //求出除本身点之前的所有点的前缀和
update_a(mp[1].x, 1);
update_len(mp[1].x, mp[1].x);
for(int i=2; i<=N; i++)
{
ll a=Query_a(mp[i].x);
ll b=Query_len(mp[i].x);
ans+=(a*mp[i].x-b)*mp[i].v;
ans+=(qzsum[i]-b-(i-1-a)*mp[i].x)*mp[i].v;
update_a(mp[i].x, 1);
update_len(mp[i].x, mp[i].x);
//printf("%lld %lld\n",a,b);
}
printf("%lld\n",ans);
}
return 0;
}