POJ 1990 MooFest 樹狀數組

  這題是我看了大白書樹狀數組後刷的第一道題,確實難度不小,因此只好上網找題解了,網上的作法確實精彩。這題的題意主要是有N頭牛,每兩頭牛之間交流的費用爲它們的距離乘上二者音量的最大值(即max(v(i),v(j))),而後統計全部牛兩兩交流的總費用。一開始能想到的作法即是O(n2)的暴力枚舉了,當時的我也只能想到這樣的複雜度,很納悶怎麼能和樹狀數組搭上邊呢?而後看了別人的題解後才驚歎其思路之妙。html

  在博客 http://www.cnblogs.com/Fatedayt/archive/2011/10/08/2202439.html 上說得很詳細,附上其主要的思路:數組

  已經說得很詳細了,即統計某頭牛i 時,經過排序和預處理能夠把本來的O(n)查詢降低到O(logn),確實很厲害,也很難想到。我結合網上其餘人的題解半抄半改寫出以下代碼:less

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 typedef long long LL;
 6 const int maxn= 20020;
 7 
 8 inline LL lowbit(LL x)    {    return x&(-x);    }
 9 
10 struct treeArray{
11     LL c[maxn], n;
12     treeArray(LL n= 0): n(n) {    memset(c,0,sizeof(c));    }
13     LL sum(LL x) {
14         LL ans= 0;
15         while(x){
16             ans+= c[x];
17             x-= lowbit(x);
18         }
19         return ans;
20     }
21     void add(LL x, LL d){
22         while(x<=n){
23             c[x]+= d;
24             x+= lowbit(x);
25         }
26     }
27 } Count(20003),dist(20003);
28 
29 struct Cow{
30     LL v,x;
31     bool operator <(const Cow c2) const {
32         return v<c2.v;
33     }
34 } cow[maxn];
35 
36 int main(){
37     int n,i;
38     scanf("%d",&n);
39     for(i=1; i<=n; ++i)
40         scanf("%lld%lld",&cow[i].v,&cow[i].x);
41     sort(cow+1,cow+n+1);
42     LL ans= 0, alldist= 0;
43     for(i=1; i<=n; ++i){
44         LL x = cow[i].x;
45         LL num = Count.sum(x);
46         LL lessdist = dist.sum(x);
47         ans += cow[i].v*(num*x-lessdist+alldist-lessdist-(i-1-num)*x);
48         Count.add(x,1);
49         dist.add(x,x);
50         alldist += x;
51     }
52     printf("%lld\n",ans);
53     return 0;
54 }

  其中,Count.sum(x)表示統計比x小的牛的個數(在上圖中就是a),dist.sum(x)表示統計比x小的牛的位置之和(在上圖中爲b);alldist即前i 頭牛的全部距離(能夠認爲是以原點做爲標準),其他的變量名也不難理解。碼完後才感到樹狀數組真是太強大了,不得不讚!spa

相關文章
相關標籤/搜索