[POJ](1900)MooFest ---- 樹狀數組★

題目傳送門

題意:

  • 有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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章