分块大法好
分块的姿势总有问题,找来HZWER的板子;
BZOJ 3343 1 //bzoj 3343
2
3
4 #include<stdio.h>
5 #include<algorithm>
6 #include<string.h>
7 #include<math.h>
8 #include<string>
9 #include<iostream>
10 using namespace std;
11 typedef long long ll;
12
13 #define N 1000002
14
15
16 int a[N],b[N],pos[N],add[N];
17 int n,Q,block,m;
18
19
20 void reset(int x)//对块内排序
21 {
22 int l=(x-1)*block+1;
23 int r=min(block*x,n);
24 for (int i=l;i<=r;i++) b[i]=a[i];
25 sort(b+l,b+r+1);
26 }
27
28 void update(int x,int y,int v)
29 {
30 if (pos[x]==pos[y])
31 for (int i=x;i<=y;i++) a[i]=a[i]+v;
32 else
33 {
34 for (int i=x;i<=pos[x]*block;i++) a[i]=a[i]+v;
35 for (int i=(pos[y]-1)*block+1;i<=y;i++) a[i]+=v;
36 }
37 reset(pos[x]);
38 reset(pos[y]);
39 for (int i=pos[x]+1;i<pos[y];i++) add[i]+=v;
40 }
41 int find(int x,int v)//在每个块内二分
42 {
43 int l=(x-1)*block+1,r=min(x*block,n);
44 int last=r;
45 while (l<=r)
46 {
47 int mid=(l+r)>>1;
48 if (b[mid]<v) l=mid+1;
49 else r=mid-1;
50 }
51 return last-l+1;
52 }
53
54 int query(int x,int y,int v)
55 {
56 int sum=0;
57 if (pos[x]==pos[y])//在一个块内
58 {
59 for (int i=x;i<=y;i++)
60 if (a[i]+add[pos[i]]>=v) sum++;
61 }
62 else//暴力处理两端
63 {
64 for (int i=x;i<=pos[x]*block;i++)
65 if (a[i]+add[pos[i]]>=v) sum++;
66 for (int i=(pos[y]-1)*block+1;i<=y;i++)
67 if (a[i]+add[pos[i]]>=v) sum++;
68 }
69 for (int i=pos[x]+1;i<pos[y];i++)//对每个块二分
70 sum+=find(i,v-add[i]);
71 return sum;
72 }
73
74 int main()
75 {
76 scanf("%d%d",&n,&Q);
77 block=sqrt(n);//每块有多少
78 for (int i=1;i<=n;i++)
79 {
80 scanf("%d",&a[i]);
81 pos[i]=(i-1)/block+1;//处于哪个块
82 }
83 if (n%block) m=n/block+1;
84 else m=n/block;
85 for (int i=1;i<=m;i++) reset(i);
86 while (Q--)
87 {
88 char s[4];
89 int x,y,v;
90 scanf("%s%d%d%d",s,&x,&y,&v);
91 if (s[0]=='M') update(x,y,v);
92 else printf("%d\n",query(x,y,v));
93 }
94 return 0;
95 }
3
4 #include<stdio.h>
5 #include<algorithm>
6 #include<string.h>
7 #include<math.h>
8 #include<string>
9 #include<iostream>
10 using namespace std;
11 typedef long long ll;
12
13 #define N 1000002
14
15
16 int a[N],b[N],pos[N],add[N];
17 int n,Q,block,m;
18
19
20 void reset(int x)//对块内排序
21 {
22 int l=(x-1)*block+1;
23 int r=min(block*x,n);
24 for (int i=l;i<=r;i++) b[i]=a[i];
25 sort(b+l,b+r+1);
26 }
27
28 void update(int x,int y,int v)
29 {
30 if (pos[x]==pos[y])
31 for (int i=x;i<=y;i++) a[i]=a[i]+v;
32 else
33 {
34 for (int i=x;i<=pos[x]*block;i++) a[i]=a[i]+v;
35 for (int i=(pos[y]-1)*block+1;i<=y;i++) a[i]+=v;
36 }
37 reset(pos[x]);
38 reset(pos[y]);
39 for (int i=pos[x]+1;i<pos[y];i++) add[i]+=v;
40 }
41 int find(int x,int v)//在每个块内二分
42 {
43 int l=(x-1)*block+1,r=min(x*block,n);
44 int last=r;
45 while (l<=r)
46 {
47 int mid=(l+r)>>1;
48 if (b[mid]<v) l=mid+1;
49 else r=mid-1;
50 }
51 return last-l+1;
52 }
53
54 int query(int x,int y,int v)
55 {
56 int sum=0;
57 if (pos[x]==pos[y])//在一个块内
58 {
59 for (int i=x;i<=y;i++)
60 if (a[i]+add[pos[i]]>=v) sum++;
61 }
62 else//暴力处理两端
63 {
64 for (int i=x;i<=pos[x]*block;i++)
65 if (a[i]+add[pos[i]]>=v) sum++;
66 for (int i=(pos[y]-1)*block+1;i<=y;i++)
67 if (a[i]+add[pos[i]]>=v) sum++;
68 }
69 for (int i=pos[x]+1;i<pos[y];i++)//对每个块二分
70 sum+=find(i,v-add[i]);
71 return sum;
72 }
73
74 int main()
75 {
76 scanf("%d%d",&n,&Q);
77 block=sqrt(n);//每块有多少
78 for (int i=1;i<=n;i++)
79 {
80 scanf("%d",&a[i]);
81 pos[i]=(i-1)/block+1;//处于哪个块
82 }
83 if (n%block) m=n/block+1;
84 else m=n/block;
85 for (int i=1;i<=m;i++) reset(i);
86 while (Q--)
87 {
88 char s[4];
89 int x,y,v;
90 scanf("%s%d%d%d",s,&x,&y,&v);
91 if (s[0]=='M') update(x,y,v);
92 else printf("%d\n",query(x,y,v));
93 }
94 return 0;
95 }
BZOJ 2120:
求区间不同数的种类,并且修改单点值。
修改操作小于1000,记录每一个颜色其前一位置。
然后分块,在同一块中每一pre排好顺序,二分其位置,得到答案。
修改暴力即可View Code
随性Code