POJ--1990(排序+树状数组)

地址:http://poj.org/problem?id=1990

题意:

给出n只,每只两个属性:

v,x

每两只的和为:sum=max(v1,v2)*fabs(x1-x2),求所有n*(n-1)/2对的和

解析:

对v值进行从小到大排序,那么对于当前羊的v值,它之前的羊都要乘这个v。

那么对于当前羊,需要求它之前的sum值。v这个问题已经解决,那么x呢?

它之前的羊的x,要么比它大,要么比它小,所以对于这个fabs的求法是不同的,需要解决这个问题。

引入两个树状数组,num[i]:比i值小的x的个数  ds[i]:比i小的x的和。

对于当前羊 i :

ll sx=getsum(st[i].x,num);

ll sm=getsum(st[i].x,ds);

求出了比羊 i 的 x 的小的x的个数,以及它们的和

所以对sum的贡献就是:

ll small=sx*st[i].x-sm;//因为当前羊的x,要被减sx次,所以直接乘sx

定义tot为羊 i 之前的x总和,那么已知比此羊小的x的和sm,那么自然就求出了比它大的和:

tot-sm

那么有:i-1-sx个st[i].x被减掉。总的来说就是:

ll big=tot-sm-(i-1-sx)*st[i].x;

剩下的就不解释了,看代码吧:

#include <cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn = 2e4+100;
ll num[maxn],ds[maxn];
int n;
struct node
{
    int v,x;
}st[maxn];
bool cmp(node a,node b){
    return a.v<b.v;
}
ll lowbit(ll x)
{
    return x&(-x);
}
ll getsum(int id,ll c[])
{
    ll an=0;
    for(int i=id;i>0;i-=lowbit(i))
        an+=c[i];
    return an;
}
void update(ll c[],int id,ll x)
{
    for(int i=id;i<maxn;i+=lowbit(i))
        c[i]+=x;
    return ;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&st[i].v,&st[i].x);
    ll all=0;
    ll tot=0;
    sort(st+1,st+1+n,cmp);
    for(int i=1;i<=n;i++)
    {
        ll sx=getsum(st[i].x,num);
        ll sm=getsum(st[i].x,ds);
        ll small=sx*st[i].x-sm;
        ll big=tot-sm-(i-1-sx)*st[i].x;
        all=all+(small+big)*st[i].v;  //记录答案
        tot+=st[i].x;  //更新i之前的和值
        update(ds,st[i].x,st[i].x);//更新比它x小和
        update(num,st[i].x,1);//更新比它x小的数目
    }
    cout<<all<<endl;
}
原文地址:https://www.cnblogs.com/liyexin/p/13090325.html