BZOJ3343 教主的魔法 分塊

2022-08-09 01:09:27 字數 3789 閱讀 2268

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

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

cyz、光哥和zjq等人不信教主的邪,於是他們有時候會問wd閉區間 [l, r] 內有多少英雄身高大於等於c,以驗證教主的魔法是否真的有效。

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

分塊演算法是指把乙個序列分成sqrt(n)塊,每塊正好有sqrt(n)個元素

對於這道題,我們先將每個數按順序分到乙個塊中,維護每個塊內部的單調性

對於乙個m操作,我們把l,r中間的塊整塊作乙個加法的標記,對於兩頭的直接暴力標

整塊不超過sqrt(n)塊,兩頭的也不超過sqrt(n)個元素,所以時間複雜度還是o(sqrt(n))

對於a操作,對於暴力的部分很容易統計,對於整塊的由於我們之前維護好了單調性,直接二分查詢就可以了

但是這裡不要忽略了之前作的add標記

145

program bzoj3343;

6const maxn=1000010;maxm=1010;7

varn,q,m,block,x,y,z,i:longint;

8 ch:char

;9 a,b,pos:array[-1

..maxn]of longint;

10 add:array[-1

..maxm]of longint;

1112

function min(a,b:longint):longint;

13begin

14if aelse

exit(b);

15end;

1617

procedure qsort(l,r:longint);

18var

i,j,mid:longint;

19begin

20 i:=l;j:=r;mid:=b[random(r-l+1)+l];

21repeat

22while (imid) do

inc(i);

23while (ldo

dec(j);

24if i<=j then

25begin

26 b[0]:=b[i];b[i]:=b[j];b[j]:=b[0

];27

inc(i);dec(j);

28end;

29 until i>j;

30if i31if l32end;

3334 procedure new

(p:longint);

35var

l,r,i:longint;

36begin

37 l:=(p-1)*block+1;r:=min(p*block,n);

38for i:=l to r do b[i]:=a[i];

39qsort(l,r);

40end;

4142

procedure update(x,y,z:longint);

43var

i:longint;

44begin

45if pos[x]=pos[y] then

46for i:=x to y do inc(a[i],z) else

47begin

48for i:=x to pos[x]*block do

inc(a[i],z);

49for i:=(pos[y]-1)*block+1 to y do

inc(a[i],z);

50end;

51for i:=pos[x]+1 to pos[y]-1

doinc(add[i],z);

52new(pos[x]);new

(pos[y]);

53end;

5455

function find(x,y:longint):longint;

56var

l,r,mid:longint;

57begin

58 find:=(x-1)*block;

59 l:=(x-1)*block+1;r:=x*block;

60while l<=r do

61begin

62 mid:=(l+r) >> 1;63

if b[mid]>=y then

64begin

65 find:=mid;l:=mid+1

;66 end else r:=mid-1;67

end;

68 dec(find,(x-1)*block);

69end;

7071

function query(x,y,z:longint):longint;

72var

tot,i:longint;

73begin

74 tot:=0;75

if pos[x]=pos[y] then

76 begin for i:=x to y do

if a[i]>=z then inc(tot);end else

77begin

78for i:=x to pos[x]*block do

if a[i]>=z then inc(tot);

79for i:=(pos[y]-1)*block+1 to y do

if a[i]>=z then inc(tot);

80end;

81for i:=pos[x]+1 to pos[y]-1

do inc(tot,find(i,z-add[i]));

82exit(tot);

83end;

8485

begin

86readln(n,q);

87 fillchar(add,sizeof(add),0

);88 block:=trunc(sqrt(n));

89for i:=1 to n do

90begin

91read(a[i]);

92 pos[i]:=(i-1) div block+1;//

pos[i]表示第i個數所在的塊

93end;

94readln;

95if n mod block=0 then m:=n div block else m:=n div block +1;96

for i:=1 to m do

new(i);

97for i:=1 to q do

98begin

99read(ch);

100if ch='m'

then

101begin

102readln(x,y,z);

103update(x,y,z);

104 end else

105begin

106readln(x,y,z);

107writeln(query(x,y,z));

108end;

109end;

110 end.

bzoj3343 教主的魔法 分塊

算是第一次寫分塊吧。這道題是最裸的分塊,每個塊上打上加標記,另外維護乙個塊內的排好序的陣列。對於修改操作,如果l,r在乙個塊內,暴力更改,之後重建。如果l,r不在乙個塊內,中間的塊處理標記,其餘部分暴力更改,之後重建。對於詢問操作,如果l,r在乙個塊內,暴力查詢 如果l,r不在乙個塊內,中間的塊裡二...

BZOJ3343 教主的魔法(分塊)

傳送門 正兒八經的分塊題。整個塊打add標記,其餘的暴力加。詢問的時候整個塊sort之後二分找,其餘的暴力找。include include include include include include using namespace std const int max n 1e6 5 const...

BZOJ3343 教主的魔法(分塊)

description 教主最近學會了一種神奇的魔法,能夠使人長高。於是他準備演示給xmyz資訊組每個英雄看。於是n個英雄們又一次聚集在了一起,這次他們排成了一列,被編號為1 2 n。每個人的身高一開始都是不超過1000的正整數。教主的魔法每次可以把閉區間 l,r 1 l r n 內的英雄的身高全部...