分块大法好

分块的姿势总有问题,找来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 ",query(x,y,v));
93     }
94     return 0;
95 }

 BZOJ 2120:

 求区间不同数的种类,并且修改单点值。

修改操作小于1000,记录每一个颜色其前一位置。

然后分块,在同一块中每一pre排好顺序,二分其位置,得到答案。

修改暴力即可View Code 

原文地址:https://www.cnblogs.com/forgot93/p/4781352.html