分块算法

算法就是将n个数序列分成块k块,每次操作时可以一次操作一块,不需要暴力挨个操作,这是分块的主要思想。

修改时,可以给每个块设置一个加法标记(就是记录这个块中元素加了多少),每次操作对每个整块直接标记,而不完整的块由于元素比较少,可以暴力修改元素的值。

查询时,何求该差不多,在块上的元素直接乘上,不完整的块暴力。

修改:

 1 void modify(int a,int b,int c)
 2 {
 3     
 4     for(int i=a;i<=min(bl[a]*blo,b);i++)
 5     {
 6         v[i]+=c;
 7         sum[bl[a]]+=c;
 8     }
 9     if(bl[a] != bl[b])
10         for(int i=(bl[b]-1)*blo+1;i<=b;i++)
11         {
12             v[i] += c;
13             sum[bl[b]] += c;            
14         }
15     for(int i=bl[a]+1;i<=bl[b]-1;i++)
16         atag[i] += c;
17 }

查询区间的和:

 1 int query(int a,int b)
 2 {
 3     int ans=0;
 4     for(int i=a;i<=min(bl[a]*blo,b);i++)
 5         ans += v[i]+add[bl[a]];
 6     if(bl[a] != bl[b])
 7         for(int i=(bl[b]-1)*blo+1;i<=b;i++)
 8             ans += v[i]+atag[bl[b]];
 9     for(int i=bl[a]+1;i<=bl[b]-1;i++)
10         ans += sum[i]+blo*add[i];
11     return ans;
12 }

合起来就这样了(模板)

 1 /*-------------------------分块*/ 
 2 const int N = 10010;
 3 int n,blo;  //block块 
 4 int bl[N];  //
 5 int v[N],add[N],sum[N];  //v数字,add增加值,sum和 
 6 
 7 void modify(int a,int b,int c)
 8 {
 9     
10     for(int i=a;i<=min(bl[a]*blo,b);i++)
11     {
12         v[i]+=c;
13         sum[bl[a]]+=c;
14     }
15     if(bl[a] != bl[b])
16         for(int i=(bl[b]-1)*blo+1;i<=b;i++)
17         {
18             v[i] += c;
19             sum[bl[b]] += c;            
20         }
21     for(int i=bl[a]+1;i<=bl[b]-1;i++)
22         atag[i] += c;
23 }
24 
25 int query(int a,int b)
26 {
27     int ans=0;
28     for(int i=a;i<=min(bl[a]*blo,b);i++)
29         ans += v[i]+add[bl[a]];
30     if(bl[a] != bl[b])
31         for(int i=(bl[b]-1)*blo+1;i<=b;i++)
32             ans += v[i]+atag[bl[b]];
33     for(int i=bl[a]+1;i<=bl[b]-1;i++)
34         ans += sum[i]+blo*add[i];
35     return ans;
36 }
37 
38 int main()
39 {
40     /*------------预处理---*/
41     scanf("%d",&n);
42     blo = sqrt(n);
43     for(int i=1; i<=n; i++)
44         scanf("%d",&v[i]);
45     for(int i=1; i<=n; i++)
46     {
47         bl[i] = (i-1)/blo+1;    //i点属于bl[i]块 
48         sum[bl[i]] += v[i];        //每一块的总和 
49     }
50     //...
51     return 0;
52 }
原文地址:https://www.cnblogs.com/mjtcn/p/6836444.html