3343: 教主的魔法
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 777 Solved: 343
[ Submit][ Status][ Discuss]
Description
教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给XMYZ信息组每个英雄看。于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1、2、……、N。
每个人的身高一开始都是不超过1000的正整数。教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W。(虽然L=R时并不符合区间的书写规范,但我们可以认为是单独增加第L(R)个英雄的身高)
CYZ、光哥和ZJQ等人不信教主的邪,于是他们有时候会问WD闭区间 [L, R] 内有多少英雄身高大于等于C,以验证教主的魔法是否真的有效。
WD巨懒,于是他把这个回答的任务交给了你。
Input
第1行为两个整数N、Q。Q为问题数与教主的施法数总和。
第2行有N个正整数,第i个数代表第i个英雄的身高。
第3到第Q+2行每行有一个操作:
(1) 若第一个字母为“M”,则紧接着有三个数字L、R、W。表示对闭区间 [L, R] 内所有英雄的身高加上W。
(2) 若第一个字母为“A”,则紧接着有三个数字L、R、C。询问闭区间 [L, R] 内有多少英雄的身高大于等于C。
Output
对每个“A”询问输出一行,仅含一个整数,表示闭区间 [L, R] 内身高大于等于C的英雄数。
Sample Input
5 3
1 2 3 4 5
A 1 5 4
M 3 5 1
A 1 5 4
1 2 3 4 5
A 1 5 4
M 3 5 1
A 1 5 4
Sample Output
2
3
3
HINT
【输入输出样例说明】
原先5个英雄身高为1、2、3、4、5,此时[1, 5]间有2个英雄的身高大于等于4。教主施法后变为1、2、4、5、6,此时[1, 5]间有3个英雄的身高大于等于4。
解题思路:
第一道分块。
分块处理序列太妖了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using
namespace
std
;
int
n
,
q
,
m
,
block
;
int
a
[
1000001
]
,
b
[
1000001
]
,
pos
[
1000001
]
,
add
[
1000001
]
;
void
reset
(
int
x
)
{
int
l
=
(
x
-
1
)
*
block
+
1
,
r
=
min
(
x
*
block
,
n
)
;
for
(
int
i
=
l
;
i
<=
r
;
i
++
)
b
[
i
]
=
a
[
i
]
;
sort
(
b
+
l
,
b
+
r
+
1
)
;
}
int
find
(
int
x
,
int
v
)
{
int
l
=
(
x
-
1
)
*
block
+
1
,
r
=
min
(
x
*
block
,
n
)
;
int
last
=
r
;
while
(
l
<=
r
)
{
int
mid
=
(
l
+
r
)
>>
1
;
if
(
b
[
mid
]
<
v
)
l
=
mid
+
1
;
else
r
=
mid
-
1
;
}
return
last
-
l
+
1
;
}
void
update
(
int
x
,
int
y
,
int
v
)
{
if
(
pos
[
x
]
==
pos
[
y
]
)
{
for
(
int
i
=
x
;
i
<=
y
;
i
++
)
a
[
i
]
=
a
[
i
]
+
v
;
}
else
{
for
(
int
i
=
x
;
i
<=
pos
[
x
]
*
block
;
i
++
)
a
[
i
]
=
a
[
i
]
+
v
;
for
(
int
i
=
(
pos
[
y
]
-
1
)
*
block
+
1
;
i
<=
y
;
i
++
)
a
[
i
]
=
a
[
i
]
+
v
;
}
reset
(
pos
[
x
]
)
;
reset
(
pos
[
y
]
)
;
for
(
int
i
=
pos
[
x
]
+
1
;
i
<
pos
[
y
]
;
i
++
)
add
[
i
]
+=
v
;
}
int
query
(
int
x
,
int
y
,
int
v
)
{
int
sum
=
0
;
if
(
pos
[
x
]
==
pos
[
y
]
)
{
for
(
int
i
=
x
;
i
<=
y
;
i
++
)
if
(
a
[
i
]
+
add
[
pos
[
i
]
]
>=
v
)
sum
++
;
}
else
{
for
(
int
i
=
x
;
i
<=
pos
[
x
]
*
block
;
i
++
)
if
(
a
[
i
]
+
add
[
pos
[
i
]
]
>=
v
)
sum
++
;
for
(
int
i
=
(
pos
[
y
]
-
1
)
*
block
+
1
;
i
<=
y
;
i
++
)
if
(
a
[
i
]
+
add
[
pos
[
i
]
]
>=
v
)
sum
++
;
}
for
(
int
i
=
pos
[
x
]
+
1
;
i
<
pos
[
y
]
;
i
++
)
sum
+=
find
(
i
,
v
-
add
[
i
]
)
;
return
sum
;
}
int
main
(
)
{
scanf
(
"%d%d"
,
&n
,
&q
)
;
block
=
int
(
sqrt
(
n
)
)
;
for
(
int
i
=
1
;
i
<=
n
;
i
++
)
{
scanf
(
"%d"
,
&a
[
i
]
)
;
pos
[
i
]
=
(
i
-
1
)
/
block
+
1
;
b
[
i
]
=
a
[
i
]
;
}
if
(
n
%
block
)
m
=
n
/
block
+
1
;
else
m
=
n
/
block
;
for
(
int
i
=
1
;
i
<=
m
;
i
++
)
reset
(
i
)
;
for
(
int
i
=
1
;
i
<=
q
;
i
++
)
{
char
ch
[
5
]
;
int
x
,
y
,
v
;
scanf
(
"%s%d%d%d"
,
ch
,
&x
,
&y
,
&v
)
;
if
(
ch
[
0
]
==
'M'
)
update
(
x
,
y
,
v
)
;
else
printf
(
"%d\n"
,
query
(
x
,
y
,
v
)
)
;
}
return
0
;
}