[POJ](1900)MooFest ---- 樹狀陣列★
阿新 • • 發佈:2018-12-10
題意:
- 有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,它前面沒有比它更小的座標了,但有比它的座標大 有 3-1頭,即這是第三頭牛,去掉他自己,比它大的有2頭,距離差就是 6 - 1+ 5-1 = 11 - 2*1 = 9
- 當前的這頭牛如果是2 ,他前面有比它小的牛的座標和是1,且有著1頭,那麼3*1(頭) - 1(前面座標比當前牛小的座標和) = 2
- 我們發現我們可以維護什麼呢?對! 座標和和牛的頭數,這樣我們就可以是用樹狀陣列了
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; }