专题总结(分块)

https://www.zybuluo.com/ysner/note/1290572

思想

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

  • 用空间换时间。
  • 复杂度永远带根号。

模板

就是(hzwer)大佬的分块(9)题。
肛了(12h)。。。

[loj6277]数列分块入门1

注意块的边界问题:

  • 单独处理左端块时要对(r)(min)
  • 特判左右端点在同一块的情况。

还有记住块的左端点为((bl[x]-1)*m+1),右端点为(bl[x]*m)

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

[loj6278]数列分块入门2

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

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

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

重置(min)(max)时记得加上标记。

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

[loj6279]数列分块入门3

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

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

[loj6280]数列分块入门4

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

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

[loj6281]数列分块入门5

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

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

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

[loj6282]数列分块入门 6

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

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

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

[loj6283]数列分块入门7

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

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

[loj6284]数列分块入门8

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

[loj6285]数列分块入门9

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

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

然后在询问中,暴力统计块(1)和块(3)中出现的数的出现次数即可。这个最高复杂度(O(2sqrt n))

于是这个问题在(O(nsqrt n))时间复杂度内得到了解决。

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

考试题

2018.9.20街灯

给一个数列({a}),每次给出(l,r,p,v),询问一个区间内模(p)等于(v)的数有多少个。

  • (nleq10^5,qleq10^5,pleq10^9,a_ileq10^4)

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

时间复杂度(O(nsqrt n))

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define ll long long
#define re register
#define il inline
#define pb(a) push_back(a)
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=1e5+100;
int A[N],n,m,f[105][105],t[10005];
struct que{int l,r,p,v,ans;}a[N];
vector<int>q[N];
il ll gi()
{
  re ll x=0,t=1;
  re char ch=getchar();
  while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  if(ch=='-') t=-1,ch=getchar();
  while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  return x*t;
}
int main()
{
  n=gi();m=gi();
  fp(i,1,n) A[i]=gi();
  fp(i,1,m)
    {
      a[i].l=gi();a[i].r=gi();a[i].p=gi();a[i].v=gi();a[i].ans=0;
      q[a[i].l-1].pb(i);q[a[i].r].pb(i);
    }
  fp(i,1,n)
    {
      ++t[A[i]];
      fp(j,1,100) ++f[j][A[i]%j];
      for(re int j=0;j<q[i].size();j++)
	{
	  re int id=q[i][j],gu=(i==a[id].r)?1:-1,p=a[id].p,v=a[id].v;
	  if(p<=100) a[id].ans+=gu*f[p][v];
	  else
	    for(re int i=0;i*p+v<=10000;i++)
	      a[id].ans+=gu*t[i*p+v];
	}
    }
  fp(i,1,m) printf("%d
",a[i].ans);
  fclose(stdin);
  fclose(stdout);
  return 0;
}
原文地址:https://www.cnblogs.com/yanshannan/p/9696317.html