1. 程式人生 > >[bzoj3343]教主的魔法

[bzoj3343]教主的魔法

log nbsp -- readn clas 數據 ans 問題 多少

題目描述

教主最近學會了一種神奇的魔法,能夠使人長高。於是他準備演示給XMYZ信息組每個英雄看。於是N個英雄們又一次聚集在了一起,這次他們排成了一列,被編號為1、2、……、N。

每個人的身高一開始都是不超過1000的正整數。教主的魔法每次可以把閉區間[L, R](1≤L≤R≤N)內的英雄的身高全部加上一個整數W。(雖然L=R時並不符合區間的書寫規範,但我們可以認為是單獨增加第L(R)個英雄的身高)

CYZ、光哥和ZJQ等人不信教主的邪,於是他們有時候會問WD閉區間 [L, R] 內有多少英雄身高大於等於C,以驗證教主的魔法是否真的有效。

WD巨懶,於是他把這個回答的任務交給了你。

輸入輸出格式

輸入格式:

第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。

輸出格式:

對每個“A”詢問輸出一行,僅含一個整數,表示閉區間 [L, R] 內身高大於等於C的英雄數。

輸入輸出樣例

輸入樣例#1:
5 3

1 2 3 4 5

A 1 5 4

M 3 5 1

A 1 5 4
輸出樣例#1:
2
3

說明

【輸入輸出樣例說明】

原先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(n*√n),完畢

源代碼

 1 #include <iostream>
 2 #include <cstdio>
 3
#include <cmath> 4 #include <algorithm> 5 #include <vector> 6 #define LL long long 7 using namespace std; 8 inline int readn(){ 9 int rtn=0,f=1;char ch=getchar(); 10 while(ch>9||ch<0){if(ch==-)f=-1;ch=getchar();} 11 while(ch<=9&&ch>=0)rtn=rtn*10+ch-0,ch=getchar(); 12 return rtn*f; 13 } 14 inline char readc(){ 15 char ch=getchar(); 16 while(ch>Z||ch<A)ch=getchar(); 17 return ch; 18 } 19 const int N=1001000; 20 int n,q,blo; 21 int v[N],bl[N]; 22 int ve[N],atag[N]; 23 void reset(int x){ 24 int l=(x-1)*blo+1,r=min(n,x*blo)+1; 25 for(int i=l;i<r;i++) 26 ve[i]=v[i]; 27 sort(ve+l,ve+r); 28 } 29 int finds(int x,int val){ 30 int l=(x-1)*blo+1,r=min(x*blo,n)+1; 31 int rtn=r-1; 32 while(l<r){ 33 int mid=(l+r)>>1; 34 if(ve[mid]<val)l=mid+1; 35 else r=mid; 36 } 37 return rtn-l+1; 38 } 39 void add(int l,int r,int m){ 40 for(int i=bl[l]+1;i<bl[r];i++)atag[i]+=m; 41 if(bl[l]==bl[r]){ 42 for(int i=l;i<=r;i++)v[i]+=m; 43 } 44 else{ 45 for(int i=l;i<=bl[l]*blo;i++)v[i]+=m; 46 for(int i=(bl[r]-1)*blo+1;i<=r;i++)v[i]+=m; 47 } 48 reset(bl[l]);reset(bl[r]); 49 } 50 51 int query(int l,int r,int c){ 52 int ans=0; 53 for(int i=bl[l]+1;i<bl[r];i++)ans+=finds(i,c-atag[i]); 54 if(bl[l]==bl[r]){ 55 for(int i=l;i<=r;i++)if(v[i]+atag[bl[i]]>=c)ans++; 56 } 57 else { 58 for(int i=l;i<=bl[l]*blo;i++)if(v[i]+atag[bl[i]]>=c)ans++; 59 for(int i=(bl[r]-1)*blo+1;i<=r;i++)if(v[i]+atag[bl[i]]>=c)ans++; 60 } 61 return ans; 62 } 63 int main(){ 64 n=readn();q=readn();blo=sqrt(n); 65 for(int i=1;i<=n;i++){ 66 bl[i]=(i-1)/blo+1; 67 v[i]=readn(); 68 } 69 for(int i=1;i<=bl[n];i++)reset(i); 70 while(q--){ 71 char opt=readc();int l=readn(),r=readn(),c=readn(); 72 if(opt==M)add(l,r,c); 73 else printf("%d\n",query(l,r,c)); 74 } 75 return 0; 76 }

[bzoj3343]教主的魔法