GOJ 1132[树状数组]

  [查看题目]

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

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

  [百度百科_树状数组]

  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


  

你可能感兴趣的:(树状数组)