[关闭]
@ysner 2018-09-27T00:37:43.000000Z 字数 2672 阅读 2090

专题总结(分块)

分块 总结


思想

把序列分成几块,然后整块整块地维护、处理信息。
:

模板

就是大佬的分块题。
肛了。。。

[loj6277]数列分块入门1

注意块的边界问题:

还有记住块的左端点为,右端点为

https://new.loj.ac/submission/207033

[loj6278]数列分块入门2

一开始没有想到在块内排序和二分。

如果要排序,每块就需要专门开存了。。。。

每次加完数后,要对边上的块进行重新排序。

重置时记得加上标记。

https://new.loj.ac/submission/207164

[loj6279]数列分块入门3

和上一道题没什么差别啊。
我基本只改了函数。

https://new.loj.ac/submission/207177

[loj6280]数列分块入门4

对每个块维护一下数字之和及加法懒标记即可。
然而竟然挂了几次细节。。。(在代码里标记了一下)

https://new.loj.ac/submission/208651

[loj6281]数列分块入门5

碰到里面数字全为的块,跳过即可。

其实我曾经设想过,在对整个块开方时,同时对存下的块中最大元素开方,但不知道为什么不可行。(见注释)
所以还是顺带扫一遍保险些。

https://new.loj.ac/submission/207274

[loj6282]数列分块入门 6

每次把数插到块里去。如果块过大,复杂度不能保证,就对所有数重新分块。

另外,中有个能把数插进序列的函数指指针位置,为插入的数。
这个函数让整个题变得非常暴力。。。

https://new.loj.ac/submission/207363

[loj6283]数列分块入门7

有点类似线段树操作。
给各块打上加法懒标记和乘法懒标记。
对区间中的边角块,先下放标记再暴力更新值。

https://new.loj.ac/submission/207496

[loj6284]数列分块入门8

这道题有点妙。
注意到每次询问区间都挺大,所以在后期很多块中都会有数字相同的情况。
于是对每个块维护表示块内数字是否相同的标记,不相同再到块里暴力修改和统计答案,相同就修改那个标记即可。
在查询边角块前必须下放标记。
https://new.loj.ac/submission/207958

[loj6285]数列分块入门9

想想查询一个区间的众数时会出现什么情况。
一个区间包含三种块,左端点块(块),右端点块(块)和其它在区间内的块(块) 。
很显然的是,在块中不是众数的数,在经过块和块的补充后,可以变成众数。
所以区间众数有三种可能:块中出现的数,及块的众数。

的信息显然需要快速查询。
于是我们要维护几个连续块的众数,及各数字出现的次数。
这些东西都可以在的时间内预处理出来。(枚举从哪一个块开始)

然后在询问中,暴力统计块和块中出现的数的出现次数即可。这个最高复杂度

于是这个问题在时间复杂度内得到了解决。

https://new.loj.ac/submission/207574

考试题

2018.9.20街灯

给一个数列,每次给出,询问一个区间内模等于的数有多少个。

这个显然只能分块做。但是和上面的不太一样。
实际上
我们先预处理出时所有答案(以前缀和的形式)。
然后处理出数字出现次数的前缀和。
每次询问,直接回答,否则暴力枚举来统计答案,这里复杂度只有(所以分块就是用来优化暴力的)。
答案都是前缀和相减的形式。

时间复杂度

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<vector>
  8. #define ll long long
  9. #define re register
  10. #define il inline
  11. #define pb(a) push_back(a)
  12. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  13. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  14. using namespace std;
  15. const int N=1e5+100;
  16. int A[N],n,m,f[105][105],t[10005];
  17. struct que{int l,r,p,v,ans;}a[N];
  18. vector<int>q[N];
  19. il ll gi()
  20. {
  21. re ll x=0,t=1;
  22. re char ch=getchar();
  23. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  24. if(ch=='-') t=-1,ch=getchar();
  25. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  26. return x*t;
  27. }
  28. int main()
  29. {
  30. n=gi();m=gi();
  31. fp(i,1,n) A[i]=gi();
  32. fp(i,1,m)
  33. {
  34. a[i].l=gi();a[i].r=gi();a[i].p=gi();a[i].v=gi();a[i].ans=0;
  35. q[a[i].l-1].pb(i);q[a[i].r].pb(i);
  36. }
  37. fp(i,1,n)
  38. {
  39. ++t[A[i]];
  40. fp(j,1,100) ++f[j][A[i]%j];
  41. for(re int j=0;j<q[i].size();j++)
  42. {
  43. re int id=q[i][j],gu=(i==a[id].r)?1:-1,p=a[id].p,v=a[id].v;
  44. if(p<=100) a[id].ans+=gu*f[p][v];
  45. else
  46. for(re int i=0;i*p+v<=10000;i++)
  47. a[id].ans+=gu*t[i*p+v];
  48. }
  49. }
  50. fp(i,1,m) printf("%d\n",a[i].ans);
  51. fclose(stdin);
  52. fclose(stdout);
  53. return 0;
  54. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注