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