生活随笔
收集整理的這篇文章主要介紹了
Bzoj 3343: 教主的魔法(分块+二分答案)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
3343: 教主的魔法
Time Limit: 10 Sec Memory Limit: 256 MB
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
Sample Output
2
3
HINT
【輸入輸出樣例說明】
原先5個英雄身高為1、2、3、4、5,此時[1, 5]間有2個英雄的身高大于等于4。教主施法后變為1、2、4、5、6,此時[1, 5]間有3個英雄的身高大于等于4。
【數據范圍】
對30%的數據,N≤1000,Q≤1000。
對100%的數據,N≤1000000,Q≤3000,1≤W≤1000,1≤C≤1,000,000,000。
/*
分塊+二分答案.
對于小塊,暴力搞.
對于整塊打標記,二分查找.
復雜度O(
q√nlogn).
(這么簡單的題怎么一開始沒想到呢QWQ.
*/
using namespace std;
int n,
m,
q,ans,belong[MAXN],a[MAXN],
s[MAXN],tag[MAXN];
int read()
{
int x=
0,f=
1;char ch=getchar();
while(ch<
'0'||ch>
'9'){
if(ch==
'-')f=-
1;ch=getchar();}
while(ch>=
'0'&&ch<=
'9')
x=
x*10+ch-
48,ch=getchar();
return x*f;
}
void pre(
int x)
{
int l=(
x-
1)
*m+
1,r=min(
x*m,n);
for(
int i=l;i<=r;i++)
s[i]=a[i];
sort(
s+l,
s+r+
1);
return ;
}
void change(
int x,
int y,
int z)
{
for(
int i=
x;i<=min(belong[
x]
*m,
y);i++) a[i]+=z;pre(belong[
x]);
if(belong[
x]+
1<belong[
y])//
1 W.
for(
int i=belong[
x]+
1;i<=belong[
y]-
1;i++) tag[i]+=z;
if(belong[
x]!=belong[
y]){
for(
int i=(belong[
y]-
1)
*m+
1;i<=
y;i++) a[i]+=z;pre(belong[
y]);}
}
int erfen(
int x,
int z)
{
int l=(
x-
1)
*m+
1,r=min(
x*m,n);
int p=lower_bound(
s+l,
s+r+
1,z-tag[
x])-
s;
return r-p+
1;
}
void query(
int x,
int y,
int z)
{ans=
0;
for(
int i=
x;i<=min(belong[
x]
*m,
y);i++)
if(a[i]+tag[belong[i]]>=z) ans++;
if(belong[
x]+
1<belong[
y])
for(
int i=belong[
x]+
1;i<=belong[
y]-
1;i++) ans+=erfen(i,z);
if(belong[
x]!=belong[
y]){
for(
int i=(belong[
y]-
1)
*m+
1;i<=
y;i++)
if(a[i]+tag[belong[i]]>=z) ans++;}
printf(
"%d\n",ans);
}
int main()
{
int x,
y,z;char ch[
3];n=
read(),
q=
read();
m=
sqrt(n);
for(
int i=
1;i<=n;i++) a[i]=
read();
for(
int i=
1;i<=n;i++) belong[i]=(i-
1)/
m+
1;
for(
int i=
1;i<=belong[n];i++) pre(i);
// 2 w.
while(
q--){scanf(
"%s",ch);
x=
read(),
y=
read(),z=
read();
if(ch[
0]==
'M') change(
x,
y,z);
else query(
x,
y,z);}
return 0;
}
轉載于:https://www.cnblogs.com/nancheng58/p/10067980.html
與50位技術專家面對面20年技術見證,附贈技術全景圖
總結
以上是生活随笔為你收集整理的Bzoj 3343: 教主的魔法(分块+二分答案)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。