GOJ 1132[树状数组]

  [查看题目]

  什么是树状数组?既然是数组,怎么可能是树状的?

  当然可以!这里说的树状并不是指物理空间上的树状,就像用数组来实现二叉堆一样,数组怎么可能是"堆"呢.下面是树状数组的结构图,对树状数组的解释百度百科上已经很详细了,这里不再详细.树状数组可以用来快速求出某个范围内数据之和,但本人觉得它最强大的是能动态快速地修改或增加数据.

  [百度百科_树状数组]

  

  题目意思是N头牛排成一行(即X轴),给出每个牛的volume threshold(听觉范围??)和一个坐标coordnate,两头牛这间交流必须至少产生一个volume值,这个volume值等于两头牛的距离乘以这两头牛的听觉的最大值.求出N头牛两两之间都进行交流时而发出的volume值之和.

  解题思路: 看完题目,最一般的解法应该马上出炉了,从左往右,枚举每头牛与后面的牛之间进行交流就可得出答案,时间复杂度为O(N^2),这个朴素解法被OJ判TLE的.

  这道题我用了数状数组A掉了,但如何应用数状数组也是一个难题.因为还要涉及贪心. 先来分析下题目:

  设有牛n1, n2, n3, n4. 其听觉值为v1, v2, v3, v4, 其坐标值为x1, x2, x3, x4.

  随便找一头牛,如n1,  n1与n2之间产生的volume值为( |x1-x2| )*max(v1, v2), 同理n1和n3: ( |x1-x3| )*max(v1, v3)......

  但如果牛的听觉值从大到小排序的(即v1>v2>v3>v4)那么n1与n2产生的volume值为( |x1-x2| )*v1, 同理与n3:( |x1-x3| )*v1...

  那么n1与其它所有的牛产生的volume值等于 (|x1-x2|+|x1-x3|+|x1-x4|)*v1. 表达式左边()里的值为距离之和.

  如何去掉绝对值符号呢?去掉之后,这个问题就迎刃而解了^ ^. 我们将x2,x3,x4数值分两类, 一类在x1的左边, 一类在x1的右边, 设左边的总数值和为sl,个数为nl右边的数值和为sr,个数为nr 那么volume=( (sr-nr*x1)+(nl*x1-sl) )*v1

  如何求出sr, sl, nl, nr的值呢? 这时候就要用到树状数组的强大功能了. 不再多说.

代码
1 #include <iostream>
2 #include <cstdio>
3 #include <string>
4 #include <cstring>
5 #include <vector>
6 #include <algorithm>
7
8  using namespace std;
9
10  const int MAXN=20010;
11 class T_Cow
12 {
13 public:
14 T_Cow(const long long& v=0, const long long& c=0):vol(v),coord(c){}
15 long long vol,coord;
16 };
17 long long N, AllNum, AllSum, Maxn;
18 vector<T_Cow> Box;
19 long long CoordNum[MAXN], CoordSum[MAXN];
20
21 bool comp(const T_Cow& a, const T_Cow& b)
22 {
23 return a.vol>b.vol;
24 }
25 long long Max(const long long a, const long long b)
26 {
27 return a<b?b:a;
28 }
29
30 long long LowBit(const long long k)
31 {
32 return k&(k^(k-1));
33 }
34
35 void Add(const long long coord, bool op)
36 {
37 long long pos=coord;
38 while( pos>0 )
39 {
40 CoordNum[pos]+=(op?1:-1);
41 CoordSum[pos]+=(op?coord:-coord);
42 pos-=LowBit(pos);
43 }
44 }
45
46 long long get_sum(long long pos, long long* box)
47 {
48 long long sum=0;
49 while( pos<=Maxn )
50 {
51 sum+=box[pos];
52 pos+=LowBit(pos);
53 }
54 return sum;
55 }
56
57 int main()
58 {
59 freopen("in", "r", stdin);
60 freopen("out", "w", stdout);
61
62 long long v, x;
63 while( scanf("%I64d", &N)!=EOF ){
64 AllNum=AllSum=Maxn=0;
65 memset(CoordNum, 0, sizeof(CoordNum));
66 memset(CoordSum, 0, sizeof(CoordSum));
67 for( int i=0; i<N; ++i )
68 {
69 scanf("%I64d%I64d", &v, &x);
70 Maxn=Max(Maxn, x);
71 AllNum++;
72 AllSum+=x;
73 Box.push_back(T_Cow(v, x));
74 }
75 vector<T_Cow>::iterator ix=Box.begin();
76 while( ix!=Box.end() )
77 {
78 Add(ix->coord, true);
79 ++ix;
80 }
81 long long ans=0, num=0, sum=0;
82 sort(Box.begin(), Box.end(), comp);
83 ix=Box.begin();
84 while( ix!=Box.end() )
85 {
86 num=get_sum(ix->coord, CoordNum);
87 sum=get_sum(ix->coord, CoordSum);
88 ans+=(2*sum-AllSum+(AllNum-2*num)*ix->coord)*ix->vol;
89 Add(ix->coord, false);
90 AllNum--;
91 AllSum-=ix->coord;
92 ++ix;
93 }
94 printf("%I64d\n", ans);
95 Box.clear();
96 }
97 return 0;
98 }
99


  

posted on 2010-11-22 14:00  Kenfly  阅读(290)  评论(0编辑  收藏  举报