[POJ](1900)MooFest ---- 树状数组★

版权声明:本文为博主原创文章,转载请预先通知博主(〃'▽'〃)。 https://blog.csdn.net/m0_37624640/article/details/82751859

题目传送门

题意:

  • 有n头牛在x轴上,每头牛具有两个属性,听力值vi和坐标xi,两头牛i,j沟通需要消耗 max(vi,vj) * abs(xi-xj)
  • 现在问你所有任意两头牛所需要消耗的总值,共n*(n-1)/2种

做法:

  • 首先暴力肯定是不行滴~
  • 我们为了优化计算,我们可以先根据牛的听力值从小到大排序。
  • 那么 ans = v1*(第1头牛与其他牛的距离差的和)+v2*(第2头牛与其他牛的距离差的和)+……+vn(第n头牛与其他牛的距离差的和)
  • 现在要优化怎么计算距离差的和的问题
  • 以题中的样例为例,我们排完序后为
  • V: 2 2 3 4
  • X: 5 6 1 3
  • 我们发现有一些牛的前面的牛 有坐标比它小的,也有比它大的。我们需要把这左右两边都计算好距离差才行。
  • 当前这头牛的坐标如果是1,它前面没有比它更小的坐标了,即0头,但有比它的坐标大 有 3-1-0头,即这是第三头牛,去掉他自己,比它大的有2头,距离差的和就是 6 - 1+ 5-1  =   11 - 2*1 = 9
  • 当前的这头牛的坐标如果是3 ,他前面有比它小的牛的坐标和是1,且有着1头,那么3*1(头) - 1(前面坐标比当前牛小的坐标和) = 2  即它与左边比它小的坐标的坐标差的和。
  • 它前面坐标比它大的有 4 - 1 - 1 = 2 头牛,它与这两头牛的坐标差的和 = 5+6+1 - 1 - 2*3 = 5 
  • 我们发现我们可以维护什么呢?对! 坐标和和牛的头数,这样我们就可以是用树状数组了

AC代码:

#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <ctime>
#define IO          ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define pb(x)       push_back(x)
#define sz(x)       (int)(x).size()
#define sc(x)       scanf("%d",&x)
#define pr(x)       printf("%d\n",x)
#define abs(x)      ((x)<0?-(x):x)
#define all(x)      x.begin(),x.end()
#define debug       printf("!!!!!!\n")
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
const double PI = 4*atan(1.0);
const int maxm = 1e8+5;
const int maxn = 2e4+5;
const int INF = 0x3f3f3f3f;
int n,m;
struct node
{
    int val;
    int pos;
}cow[maxn];
int tree[2][maxn];//维护两个树状数组
inline ll read()
{
    char x;
    int flag = 0;
    while(x = getchar(),x<'0' || x>'9') if(x == '-') flag = 1;
    ll u = x-'0';
    while(x = getchar(),x>='0' && x<='9') u = (u<<3)+(u<<1)+x-'0';
    if(flag) u = -u;
    return u;
}
inline ll lowbit(ll x){return x&(-x);}
void update(ll x,ll val,int flag)
{
    for(ll i=x;i<=maxn;i+=lowbit(i)) tree[flag][i]+=val;
}
ll query(ll x,int flag)
{
    ll res = 0;
    for(int i=x;i;i-=lowbit(i)) res+=tree[flag][i];
    return res;
}
bool cmp(node a,node b)
{
    if(a.val == b.val) return a.pos<b.pos;
    else return a.val<b.val;
}
int main()
{
    #ifdef LOCAL_FILE
    freopen("in.txt","r",stdin);
    #endif // LOCAL_FILE
    n = read();
    for(int i=1;i<=n;i++)
    {
        cow[i].val = read();
        cow[i].pos = read();
    }
    sort(cow+1,cow+1+n,cmp);
    ll res = 0;
    for(int i=1;i<=n;i++)
    {
        ll num = query(cow[i].pos,0); //表示比当前的牛pos小的有几头
        ll prep = query(cow[i].pos,1);//表示比当前的牛pos小的牛的pos和
        ll l = num*cow[i].pos-prep; //当前牛与其pos前面的差值
        ll r = query(maxn,1)-prep-(i-1-num)*cow[i].pos; //当前牛与其pos后面的差值
        res += (l+r)*cow[i].val;
        update(cow[i].pos,1,0);
        update(cow[i].pos,cow[i].pos,1);
    }
    printf("%lld\n",res);
    #ifdef LOCAL_FILE
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << "ms." << endl;
    #endif // LOCAL_FILE
    return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_37624640/article/details/82751859