[BZOJ3343]教主的魔法|分块
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巨懒,于是他把这个回答的任务交给了你。
分块算法是指把一个序列分成sqrt(n)块,每块正好有sqrt(n)个元素
对于这道题,我们先将每个数按顺序分到一个块中,维护每个块内部的单调性
对于一个M操作,我们把l,r中间的块整块作一个加法的标记,对于两头的直接暴力标
整块不超过sqrt(n)块,两头的也不超过sqrt(n)个元素,所以时间复杂度还是O(sqrt(n))
对于A操作,对于暴力的部分很容易统计,对于整块的由于我们之前维护好了单调性,直接二分查找就可以了
但是这里不要忽略了之前作的add标记
1 { 2 Chunk. 3 } 4 5 program bzoj3343; 6 const maxn=1000010;maxm=1010; 7 var n,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; 11 12 function min(a,b:longint):longint; 13 begin 14 if a<b then exit(a) else exit(b); 15 end; 16 17 procedure qsort(L,R:longint); 18 var i,j,mid:longint; 19 begin 20 i:=L;j:=R;mid:=b[random(R-L+1)+L]; 21 repeat 22 while (i<R)and(b[i]>mid) do inc(i); 23 while (L<j)and(b[j]<mid) do dec(j); 24 if i<=j then 25 begin 26 b[0]:=b[i];b[i]:=b[j];b[j]:=b[0]; 27 inc(i);dec(j); 28 end; 29 until i>j; 30 if i<R then qsort(i,R); 31 if L<j then qsort(L,j); 32 end; 33 34 procedure new(p:longint); 35 var l,r,i:longint; 36 begin 37 l:=(p-1)*block+1;r:=min(p*block,n); 38 for i:=l to r do b[i]:=a[i]; 39 qsort(l,r); 40 end; 41 42 procedure update(x,y,z:longint); 43 var i:longint; 44 begin 45 if pos[x]=pos[y] then 46 for i:=x to y do inc(a[i],z) else 47 begin 48 for i:=x to pos[x]*block do inc(a[i],z); 49 for i:=(pos[y]-1)*block+1 to y do inc(a[i],z); 50 end; 51 for i:=pos[x]+1 to pos[y]-1 do inc(add[i],z); 52 new(pos[x]);new(pos[y]); 53 end; 54 55 function find(x,y:longint):longint; 56 var L,R,mid:longint; 57 begin 58 find:=(x-1)*block; 59 L:=(x-1)*block+1;R:=x*block; 60 while L<=R do 61 begin 62 mid:=(L+R) >> 1; 63 if b[mid]>=y then 64 begin 65 find:=mid;L:=mid+1; 66 end else R:=mid-1; 67 end; 68 dec(find,(x-1)*block); 69 end; 70 71 function query(x,y,z:longint):longint; 72 var tot,i:longint; 73 begin 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 77 begin 78 for i:=x to pos[x]*block do if a[i]>=z then inc(tot); 79 for i:=(pos[y]-1)*block+1 to y do if a[i]>=z then inc(tot); 80 end; 81 for i:=pos[x]+1 to pos[y]-1 do inc(tot,find(i,z-add[i])); 82 exit(tot); 83 end; 84 85 begin 86 readln(n,q); 87 fillchar(add,sizeof(add),0); 88 block:=trunc(sqrt(n)); 89 for i:=1 to n do 90 begin 91 read(a[i]); 92 pos[i]:=(i-1) div block+1;//pos[i]表示第i个数所在的块 93 end; 94 readln; 95 if n mod block=0 then m:=n div block else m:=n div block +1; 96 for i:=1 to m do new(i); 97 for i:=1 to q do 98 begin 99 read(ch); 100 if ch='M' then 101 begin 102 readln(x,y,z); 103 update(x,y,z); 104 end else 105 begin 106 readln(x,y,z); 107 writeln(query(x,y,z)); 108 end; 109 end; 110 end.