洛谷 教主的魔法

题目链接

题解

分块。
先分块,然后对每一个块内排序。
修改时对于处于一个块内的暴力修改后重新排序,对于处于不同块的把最左最右两个不完整的块暴力修改,然后对中间的块打标记。
查询时对整个块直接二分查询,对不完整的块就暴力查询。
时间复杂度:$O(Q\sqrt{N} \log N)$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cctype>
#define INF 2000000000
using namespace std;
typedef long long ll;
int n,m,h[1000005],bid[1000005],siz;
//偷懒的做法。
int t[1005][1005],add[1005],vis[1005],S[1005]={0};
int read(){
int f=1,x=0;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
return f*x;
}
int query(int L,int R,int C){
int ans=0;
for(;bid[L]==bid[L-1];L++)
if(h[L]>=C-add[bid[L]])ans++;
for(;bid[R]==bid[R+1];R--)
if(h[R]>=C-add[bid[R]])ans++;
for(int i=bid[L];i<=bid[R];i++){
if(vis[i]){
for(int j=0;bid[L]==i;L++)
t[i][j++]=h[L];
sort(t[i],t[i]+S[i]);
ans+=(t[i]+S[i])-lower_bound(t[i],t[i]+S[i],C-add[i]);
vis[i]=0;
}else
ans+=(t[i]+S[i])-lower_bound(t[i],t[i]+S[i],C-add[i]);
}
return ans;
}
void update(int L,int R,int W){
for(;bid[L]==bid[L-1];L++)h[L]+=W;
vis[bid[L-1]]=1;
for(;bid[R]==bid[R+1];R--)h[R]+=W;
vis[bid[R+1]]=1;
for(int i=bid[L];i<=bid[R];i++)
add[i]+=W;
}
void init(){
n=read(),m=read();
for(siz=1;siz*siz<n;siz++);
for(int i=1;i<=n;i++)
h[i]=read(),
bid[i]=(i-1)/siz+1,
S[bid[i]]++;
bid[n+1]=siz+1;
}
void solve(){
int x,y,z;
char ord[3];
fill(vis+1,vis+siz+1,1);
for(int i=1;i<=m;i++){
scanf("%s%d%d%d",ord,&x,&y,&z);
if(ord[0]=='A')
printf("%d\n",query(x,y,z));
else
update(x,y,z);
}
}
int main(){
init();
solve();
return 0;
}