菜鸡的 分块 刷题记录

洛谷P2801 教主的魔法

  • 题意:区间加,然后查询区间内大于a的数.
  • 做法:对于每个块维护一个它的排好序的序列,每次查找lowerbound就星,不是整块的就暴力。

           然后注意每次加的时候不是整块的那部分原有顺序会被破坏,暴力再排序就是。

  • 代码:
 1 #include <bits/stdc++.h>
 2 #define nmax 1000005
 3 
 4 using namespace std;
 5 int a[nmax],b[nmax],p[nmax],add[nmax]={0};
 6 int n,bn,m,q;
 7 
 8 inline void reset(int x){ //把块x的排序
 9     int r=bn*x,l=bn*(x-1)+1;
10     for (int i=l; i<=r; i++) b[i]=a[i];
11     sort(b+l,b+r+1);
12 }
13 
14 void build(){
15     cin>>n>>q;
16     bn=sqrt(n);
17     m=n/bn;
18     if(n%bn) m++;
19     for (int i=0; i<n; i++){
20         scanf("%d",&a[i+1]);
21         p[i+1]=i/bn+1;
22     }
23     for (int i=1; i<=m; i++) reset(i);
24 }
25 
26 inline int find(int l,int r,int x){
27     int ans=0;
28     for (int i=l; i<=r; i++) if(a[i]>=x) ans++;
29     return ans;
30 }
31 
32 inline void update(int l,int r,int x){
33     if(p[l]==p[r]) {
34             for (int i=l; i<=r; i++) a[i]+=x;
35             reset(p[l]);
36             return;
37     }
38     for (int i=p[l]+1; i<p[r]; i++) add[i]+=x;
39     for (int i=l; i<=p[l]*bn; i++) a[i]+=x;
40     reset(p[l]);
41     for (int i=(p[r]-1)*bn+1; i<=r; i++) a[i]+=x;
42     reset(p[r]);
43 }
44 
45 inline int query(int l,int r,int x){
46     int ta,ans=0;
47     if(p[l]==p[r]) return find(l,r,x-add[ p[l] ]);
48     for (int i=p[l]+1; i<p[r]; i++) {
49         int r=bn*i,l=bn*(i-1)+1;
50         ta=lower_bound(b+l,b+r+1,x-add[i])-(b+l);
51         ans+=bn-ta;
52     }
53     ans+=find( l,p[l]*bn,x-add[ p[l] ]);
54     ans+=find( (p[r]-1)*bn+1 ,r,x-add[ p[r] ]);
55     return ans;
56 }
57 
58 int main(){
59     freopen("testdata.in","r",stdin);
60     build();
61     char in[10];
62     int l,r,t;
63     for (int i=0; i<q; i++) {
64         scanf("%s%d%d%d",in,&l,&r,&t);
65         if(in[0]=='M') update(l,r,t);
66         else printf("%d\n",query(l,r,t));
67     }
68     return 0;
69 }
View Code
  • 基本上照着hzwer学长打的,orz感谢这么好的分块教程。

猜你喜欢

转载自www.cnblogs.com/jiecaoer/p/11255742.html